Moved octoprint sources to "src" folder, adjusted setup.py and run script accordingly

This commit is contained in:
Gina Häußge 2013-09-15 21:45:31 +02:00
parent a87541c354
commit 51ae782f02
133 changed files with 1699 additions and 1670 deletions

View file

@ -1,2 +1,2 @@
recursive-include octoprint/static *
recursive-include octoprint/templates *
recursive-include src/octoprint/static *
recursive-include src/octoprint/templates *

View file

@ -1 +0,0 @@

View file

@ -6,3 +6,5 @@ PyYAML==3.10
Flask-Login==0.2.2
Flask-Principal==0.3.5
netaddr>=0.7.10
mock>=1.0.1
nose>=1.3.0

View file

@ -5,7 +5,6 @@ sockjs-tornado>=1.0.0
PyYAML==3.10
Flask-Login==0.2.2
Flask-Principal==0.3.5
numpy>=1.6.2
pyserial>=2.6
netaddr>=0.7.10
mock>=1.0.1

75
run
View file

@ -1,65 +1,16 @@
#!/usr/bin/env python
print """
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! You are using an old startup method for OctoPrint. !!!
!!! Please perform 'sudo python setup.py install' and !!!
!!! use the 'octoprint' executable instead. !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
"""
import sys
from octoprint.daemon import Daemon
from octoprint.server import Server
sys.path.append("src")
class Main(Daemon):
def __init__(self, pidfile, configfile, basedir, host, port, debug):
Daemon.__init__(self, pidfile)
self._configfile = configfile
self._basedir = basedir
self._host = host
self._port = port
self._debug = debug
def run(self):
octoprint = Server(self._configfile, self._basedir, self._host, self._port, self._debug)
octoprint.run()
def main():
import argparse
parser = argparse.ArgumentParser(prog="run")
parser.add_argument("-d", "--debug", action="store_true", dest="debug",
help="Enable debug mode")
parser.add_argument("--host", action="store", type=str, dest="host",
help="Specify the host on which to bind the server")
parser.add_argument("--port", action="store", type=int, dest="port",
help="Specify the port on which to bind the server")
parser.add_argument("-c", "--config", action="store", dest="config",
help="Specify the config file to use. OctoPrint needs to have write access for the settings dialog to work. Defaults to ~/.octoprint/config.yaml")
parser.add_argument("-b", "--basedir", action="store", dest="basedir",
help="Specify the basedir to use for uploads, timelapses etc. OctoPrint needs to have write access. Defaults to ~/.octoprint")
parser.add_argument("--daemon", action="store", type=str, choices=["start", "stop", "restart"],
help="Daemonize/control daemonized OctoPrint instance (only supported under Linux right now)")
parser.add_argument("--pid", action="store", type=str, dest="pidfile", default="/tmp/octoprint.pid",
help="Pidfile to use for daemonizing, defaults to /tmp/octoprint.pid")
parser.add_argument("--iknowwhatimdoing", action="store_true", dest="allowRoot",
help="Allow OctoPrint to run as user root")
args = parser.parse_args()
if args.daemon:
if sys.platform == "darwin" or sys.platform == "win32":
print >> sys.stderr, "Sorry, daemon mode is only supported under Linux right now"
sys.exit(2)
daemon = Main(args.pidfile, args.config, args.basedir, args.host, args.port, args.debug)
if "start" == args.daemon:
daemon.start()
elif "stop" == args.daemon:
daemon.stop()
elif "restart" == args.daemon:
daemon.restart()
else:
octoprint = Server(args.config, args.basedir, args.host, args.port, args.debug, args.allowRoot)
octoprint.run()
if __name__ == "__main__":
main()
import octoprint
octoprint.main()

0
octoprint.init → scripts/octoprint.init Executable file → Normal file
View file

View file

@ -3,7 +3,7 @@
from setuptools import setup, find_packages
VERSION = "0.1.0"
VERSION = "1.1.0-dev"
def params():
name = "OctoPrint"
@ -34,11 +34,23 @@ def params():
url = "http://octoprint.org"
license = "AGPLv3"
packages = find_packages()
packages = find_packages(where="src")
package_dir = {"octoprint": "src/octoprint"}
include_package_data = True
zip_safe = False
install_requires = open("requirements.txt").read().split("\n")
entry_points = {
"console_scripts": [
"octoprint = octoprint:main"
]
}
#scripts = {
# "scripts/octoprint.init": "/etc/init.d/octoprint"
#}
return locals()
setup(**params())

66
src/octoprint/__init__.py Normal file
View file

@ -0,0 +1,66 @@
#!/usr/bin/env python
import sys
from octoprint.daemon import Daemon
from octoprint.server import Server
class Main(Daemon):
def __init__(self, pidfile, configfile, basedir, host, port, debug):
Daemon.__init__(self, pidfile)
self._configfile = configfile
self._basedir = basedir
self._host = host
self._port = port
self._debug = debug
def run(self):
octoprint = Server(self._configfile, self._basedir, self._host, self._port, self._debug)
octoprint.run()
def main():
import argparse
parser = argparse.ArgumentParser(prog="run")
parser.add_argument("-d", "--debug", action="store_true", dest="debug",
help="Enable debug mode")
parser.add_argument("--host", action="store", type=str, dest="host",
help="Specify the host on which to bind the server")
parser.add_argument("--port", action="store", type=int, dest="port",
help="Specify the port on which to bind the server")
parser.add_argument("-c", "--config", action="store", dest="config",
help="Specify the config file to use. OctoPrint needs to have write access for the settings dialog to work. Defaults to ~/.octoprint/config.yaml")
parser.add_argument("-b", "--basedir", action="store", dest="basedir",
help="Specify the basedir to use for uploads, timelapses etc. OctoPrint needs to have write access. Defaults to ~/.octoprint")
parser.add_argument("--daemon", action="store", type=str, choices=["start", "stop", "restart"],
help="Daemonize/control daemonized OctoPrint instance (only supported under Linux right now)")
parser.add_argument("--pid", action="store", type=str, dest="pidfile", default="/tmp/octoprint.pid",
help="Pidfile to use for daemonizing, defaults to /tmp/octoprint.pid")
parser.add_argument("--iknowwhatimdoing", action="store_true", dest="allowRoot",
help="Allow OctoPrint to run as user root")
args = parser.parse_args()
if args.daemon:
if sys.platform == "darwin" or sys.platform == "win32":
print >> sys.stderr, "Sorry, daemon mode is only supported under Linux right now"
sys.exit(2)
daemon = Main(args.pidfile, args.config, args.basedir, args.host, args.port, args.debug)
if "start" == args.daemon:
daemon.start()
elif "stop" == args.daemon:
daemon.stop()
elif "restart" == args.daemon:
daemon.restart()
else:
octoprint = Server(args.config, args.basedir, args.host, args.port, args.debug, args.allowRoot)
octoprint.run()
if __name__ == "__main__":
main()

View file

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 135 KiB

View file

Before

Width:  |  Height:  |  Size: 890 B

After

Width:  |  Height:  |  Size: 890 B

View file

Before

Width:  |  Height:  |  Size: 112 B

After

Width:  |  Height:  |  Size: 112 B

View file

@ -1,161 +1,161 @@
/*body,*/
/*#wrap {*/
/*width:1000px;*/
/*height: 680px;*/
/*position: absolute;*/
/*top: 50%;*/
/*margin-top: -350px;*/
/*left: 50%;*/
/*margin-left: -500px;*/
/**/
/*background:#ffffff;*/
/*border: 5px outset #bbb;*/
/*-moz-border-radius: 5px;*/
/*-webkit-border-radius: 5px;*/
/*border-radius: 5px;*/
/*}*/
/*#control {*/
/*float:left;*/
/*width:300px;*/
/*margin-top: 10px;*/
/*margin-left: 10px;*/
/*background:#ffffff;*/
/*margin-right: 10px;*/
/*height: 680px;*/
/*}*/
#file_block {
/*margin-top: 20px;*/
/*margin-left: 20px;*/
}
#control_bottom {
position: absolute;
bottom: 0;
width: 300px;
margin-bottom: 10px;
}
#options{
float: left;
margin-left: 5px;
margin-bottom: 5px;
}
/*#gcode {
background: #ffffff;
float:right;
width: 680px;
height: 680px;
border-width: 2px;
border-style: none none none solid;
}*/
#canvas{
/*float: left;*/
clear:none;
}
#drop_zone {
border: 2px dashed #bbb;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 40px;
margin: 5px;
text-align: center;
font: 20pt bold;
color: #bbb
}
#slider-vertical {
/*position: absolute;*/
/*right: 0;*/
/*top: 0;*/
height: 580px;
width: 10px;
float: right;
}
#slider-horizontal {
height: 10px;
width: 570px;
/*position: absolute;*/
/*bottom: 0;*/
}
#main_button_block {
/*float: right;*/
margin-bottom: 5px;
margin-right: 5px;
}
#gcode .mbut{
height:60px;
width: 250px;
font-size: 1em;
}
#tabs-min {
height: 680px;
padding: 0px;
}
#gcode .mtab{
background: transparent;
border: none;
font-weight: normal;
font-size: 0.5em;
}
#gcode .mtab-defstate{
background: transparent;
border: none;
}
#gcode .mtab-content{
background: #ffffff;
background-image: none;
border: 0px none #dddddd;
border-bottom-style: none;
margin: 0px;
}
#gcode .bar {
-webkit-transition: width 0s linear !important;
-moz-transition: width 0s linear !important;
-o-transition: width 0s linear !important;
transition: width 0s linear !important;
}
#gcode .nav {
margin-bottom: 0px !important;
}
#gcode .tab-content {
overflow: visible;
}
#gcode .aboutpage {
margin: 10px;
}
#accordion_top .ui-accordion-content{
padding: 5px;
}
#tabs-min .ui-tabs-panel {
padding: 0px;
}
#progressBlock {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 10px;
}
#gcode .colorBox {
width: 50px;
height: 15px;
border: 1px solid #000000;
float:left;
}
#gcode .activeline {background: #fff0b6 !important;}
/*body,*/
/*#wrap {*/
/*width:1000px;*/
/*height: 680px;*/
/*position: absolute;*/
/*top: 50%;*/
/*margin-top: -350px;*/
/*left: 50%;*/
/*margin-left: -500px;*/
/**/
/*background:#ffffff;*/
/*border: 5px outset #bbb;*/
/*-moz-border-radius: 5px;*/
/*-webkit-border-radius: 5px;*/
/*border-radius: 5px;*/
/*}*/
/*#control {*/
/*float:left;*/
/*width:300px;*/
/*margin-top: 10px;*/
/*margin-left: 10px;*/
/*background:#ffffff;*/
/*margin-right: 10px;*/
/*height: 680px;*/
/*}*/
#file_block {
/*margin-top: 20px;*/
/*margin-left: 20px;*/
}
#control_bottom {
position: absolute;
bottom: 0;
width: 300px;
margin-bottom: 10px;
}
#options{
float: left;
margin-left: 5px;
margin-bottom: 5px;
}
/*#gcode {
background: #ffffff;
float:right;
width: 680px;
height: 680px;
border-width: 2px;
border-style: none none none solid;
}*/
#canvas{
/*float: left;*/
clear:none;
}
#drop_zone {
border: 2px dashed #bbb;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 40px;
margin: 5px;
text-align: center;
font: 20pt bold;
color: #bbb
}
#slider-vertical {
/*position: absolute;*/
/*right: 0;*/
/*top: 0;*/
height: 580px;
width: 10px;
float: right;
}
#slider-horizontal {
height: 10px;
width: 570px;
/*position: absolute;*/
/*bottom: 0;*/
}
#main_button_block {
/*float: right;*/
margin-bottom: 5px;
margin-right: 5px;
}
#gcode .mbut{
height:60px;
width: 250px;
font-size: 1em;
}
#tabs-min {
height: 680px;
padding: 0px;
}
#gcode .mtab{
background: transparent;
border: none;
font-weight: normal;
font-size: 0.5em;
}
#gcode .mtab-defstate{
background: transparent;
border: none;
}
#gcode .mtab-content{
background: #ffffff;
background-image: none;
border: 0px none #dddddd;
border-bottom-style: none;
margin: 0px;
}
#gcode .bar {
-webkit-transition: width 0s linear !important;
-moz-transition: width 0s linear !important;
-o-transition: width 0s linear !important;
transition: width 0s linear !important;
}
#gcode .nav {
margin-bottom: 0px !important;
}
#gcode .tab-content {
overflow: visible;
}
#gcode .aboutpage {
margin: 10px;
}
#accordion_top .ui-accordion-content{
padding: 5px;
}
#tabs-min .ui-tabs-panel {
padding: 0px;
}
#progressBlock {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 10px;
}
#gcode .colorBox {
width: 50px;
height: 15px;
border: 1px solid #000000;
float:left;
}
#gcode .activeline {background: #fff0b6 !important;}

View file

@ -1,473 +1,473 @@
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/24/12
* Time: 12:18 PM
*/
var gcode;
var firstReport;
var z_heights = {};
var model = [];
var gCodeOptions = {
sortLayers: false,
purgeEmptyLayers: true,
analyzeModel: false
};
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var filamentByLayer = {};
var totalFilament=0;
var printTime=0;
var printTimeByLayer = {};
var layerHeight=0;
var layerCnt = 0;
var speeds = {extrude: [], retract: [], move: []};
var speedsByLayer = {extrude: {}, retract: {}, move: {}};
var sendLayerToParent = function(layerNum, z, progress){
self.postMessage({
"cmd": "returnLayer",
"msg": {
cmds: model[layerNum],
layerNum: layerNum,
zHeightObject: {zValue: z, layer: z_heights[z]},
isEmpty: false,
progress: progress
}
});
};
var sendMultiLayerToParent = function(layerNum, z, progress){
var tmpModel = [];
var tmpZHeight = {};
for(var i=0;i<layerNum.length;i++){
tmpModel[layerNum[i]] = model[layerNum[i]];
tmpZHeight[layerNum[i]] = z_heights[z[i]];
}
self.postMessage({
"cmd": "returnMultiLayer",
"msg": {
model: tmpModel,
layerNum: layerNum,
zHeightObject: {zValue: z, layer: tmpZHeight},
isEmpty: false,
progress: progress
}
});
};
var sendSizeProgress = function(progress){
self.postMessage({
"cmd": "analyzeProgress",
"msg": {
progress: progress,
printTime: printTime
}
});
};
var sendAnalyzeDone = function(){
self.postMessage({
"cmd": "analyzeDone",
"msg": {
max: max,
min: min,
modelSize: modelSize,
totalFilament:totalFilament,
filamentByLayer: filamentByLayer,
printTime: printTime,
layerHeight: layerHeight,
layerCnt: layerCnt,
layerTotal: model.length,
speeds: speeds,
speedsByLayer: speedsByLayer,
printTimeByLayer: printTimeByLayer
}
});
};
var purgeLayers = function(){
var purge=true;
for(var i=0;i<model.length;i++){
purge=true;
if(!model[i])purge=true;
else {
for(var j=0;j<model[i].length;j++){
if(model[i][j].extrude)purge=false;
}
}
if(!purge){
layerCnt+=1;
}
}
// self.postMessage('LayerCnt: ' + layerCnt);
};
var analyzeModel = function(){
var i,j;
var x_ok=false, y_ok=false;
var cmds;
var tmp1= 0, tmp2=0;
var speedIndex=0;
var type;
var printTimeAdd=0;
// var moveTime=0;
for(i=0;i<model.length;i++){
cmds = model[i];
if(!cmds)continue;
for(j=0;j<cmds.length;j++){
x_ok=false;
y_ok=false;
if(typeof(cmds[j].x) !== 'undefined'&&typeof(cmds[j].prevX) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].x))
{
max.x = parseFloat(max.x)>parseFloat(cmds[j].x)?parseFloat(max.x):parseFloat(cmds[j].x);
max.x = parseFloat(max.x)>parseFloat(cmds[j].prevX)?parseFloat(max.x):parseFloat(cmds[j].prevX);
min.x = parseFloat(min.x)<parseFloat(cmds[j].x)?parseFloat(min.x):parseFloat(cmds[j].x);
min.x = parseFloat(min.x)<parseFloat(cmds[j].prevX)?parseFloat(min.x):parseFloat(cmds[j].prevX);
x_ok=true;
}
if(typeof(cmds[j].y) !== 'undefined'&&typeof(cmds[j].prevY) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].y)){
max.y = parseFloat(max.y)>parseFloat(cmds[j].y)?parseFloat(max.y):parseFloat(cmds[j].y);
max.y = parseFloat(max.y)>parseFloat(cmds[j].prevY)?parseFloat(max.y):parseFloat(cmds[j].prevY);
min.y = parseFloat(min.y)<parseFloat(cmds[j].y)?parseFloat(min.y):parseFloat(cmds[j].y);
min.y = parseFloat(min.y)<parseFloat(cmds[j].prevY)?parseFloat(min.y):parseFloat(cmds[j].prevY);
y_ok=true;
}
if(typeof(cmds[j].prevZ) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].prevZ)){
max.z = parseFloat(max.z)>parseFloat(cmds[j].prevZ)?parseFloat(max.z):parseFloat(cmds[j].prevZ);
min.z = parseFloat(min.z)<parseFloat(cmds[j].prevZ)?parseFloat(min.z):parseFloat(cmds[j].prevZ);
}
if(typeof(cmds[j].extrude) !== 'undefined'||cmds[j].retract!=0){
totalFilament+=cmds[j].extrusion;
if(!filamentByLayer[cmds[j].prevZ])filamentByLayer[cmds[j].prevZ]=0;
filamentByLayer[cmds[j].prevZ]+=cmds[j].extrusion;
}
if(x_ok&&y_ok){
printTimeAdd = Math.sqrt(Math.pow(parseFloat(cmds[j].x)-parseFloat(cmds[j].prevX),2)+Math.pow(parseFloat(cmds[j].y)-parseFloat(cmds[j].prevY),2))/(cmds[j].speed/60);
}else if(cmds[j].retract===0&&cmds[j].extrusion!==0){
tmp1 = Math.sqrt(Math.pow(parseFloat(cmds[j].x)-parseFloat(cmds[j].prevX),2)+Math.pow(parseFloat(cmds[j].y)-parseFloat(cmds[j].prevY),2))/(cmds[j].speed/60);
tmp2 = Math.abs(parseFloat(cmds[j].extrusion)/(cmds[j].speed/60));
printTimeAdd = tmp1>=tmp2?tmp1:tmp2;
}else if(cmds[j].retract!==0){
printTimeAdd = Math.abs(parseFloat(cmds[j].extrusion)/(cmds[j].speed/60));
}
printTime += printTimeAdd;
if(typeof(printTimeByLayer[cmds[j].prevZ])==='undefined'){printTimeByLayer[cmds[j].prevZ]=0;}
printTimeByLayer[cmds[j].prevZ] += printTimeAdd;
if(cmds[j].extrude&&cmds[j].retract===0){
type = 'extrude';
}else if(cmds[j].retract!==0){
type = 'retract';
}else if(!cmds[j].extrude&&cmds[j].retract===0){
type = 'move';
// if(cmds[j].prevZ == '17.1'){
// self.postMessage({cmd: 'Got speed ' + cmds[j].speed + 'with line ' + cmds[j].gcodeLine});
// }
}else {
self.postMessage({cmd: 'unknown type of move'});
type = 'unknown';
}
speedIndex = speeds[type].indexOf(cmds[j].speed);
if (speedIndex === -1) {
speeds[type].push(cmds[j].speed);
speedIndex = speeds[type].indexOf(cmds[j].speed);
}
if(typeof(speedsByLayer[type][cmds[j].prevZ]) === 'undefined'){
speedsByLayer[type][cmds[j].prevZ] = [];
}
if(speedsByLayer[type][cmds[j].prevZ].indexOf(cmds[j].speed) === -1){
speedsByLayer[type][cmds[j].prevZ][speedIndex] = cmds[j].speed;
}
}
sendSizeProgress(i/model.length*100);
}
purgeLayers();
modelSize.x = Math.abs(max.x - min.x);
modelSize.y = Math.abs(max.y - min.y);
modelSize.z = Math.abs(max.z - min.z);
layerHeight = (max.z-min.z)/(layerCnt-1);
sendAnalyzeDone();
};
var doParse = function(){
var argChar, numSlice;
model=[];
var sendLayer = undefined;
var sendLayerZ = 0;
var sendMultiLayer = [];
var sendMultiLayerZ = [];
var lastSend = 0;
// console.time("parseGCode timer");
var reg = new RegExp(/^(?:G0|G1)\s/i);
var comment = new RegExp()
var j, layer= 0, extrude=false, prevRetract= 0, retract=0, x, y, z=0, f, prevZ=0, prevX, prevY,lastF=4000, prev_extrude = {a: undefined, b: undefined, c: undefined, e: undefined, abs: undefined}, extrudeRelative=false;
var dcExtrude=false;
var assumeNonDC = false;
for(var i=0;i<gcode.length;i++){
x=undefined;
y=undefined;
z=undefined;
retract = 0;
var line = gcode[i].line;
var percentage = gcode[i].percentage;
extrude=false;
line = line.split(/[\(;]/)[0];
if(reg.test(line)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
z = Number(z);
if(z == prevZ) continue;
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
sendLayer = layer;
sendLayerZ = z;
prevZ = z;
break;
case 'e':
case 'a':
case 'b':
case 'c':
assumeNonDC = true;
numSlice = parseFloat(args[j].slice(1)).toFixed(3);
if(!extrudeRelative){
// absolute extrusion positioning
prev_extrude["abs"] = parseFloat(numSlice)-parseFloat(prev_extrude[argChar]);
}else{
prev_extrude["abs"] = parseFloat(numSlice);
}
extrude = prev_extrude["abs"]>0;
if(prev_extrude["abs"]<0){
prevRetract = -1;
retract = -1;
}
else if(prev_extrude["abs"]==0){
retract = 0;
}else if(prev_extrude["abs"]>0&&prevRetract < 0){
prevRetract = 0;
retract = 1;
} else {
retract = 0;
}
prev_extrude[argChar] = numSlice;
break;
case 'f':
numSlice = args[j].slice(1);
lastF = numSlice;
break;
default:
break;
}
}
if(dcExtrude&&!assumeNonDC){
extrude = true;
prev_extrude["abs"] = Math.sqrt((prevX-x)*(prevX-x)+(prevY-y)*(prevY-y));
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i), percentage: percentage};
//{x: x, y: y, z: z, extrude: extrude, retract: retract, noMove: false, extrusion: (extrude||retract)?prev_extrude["abs"]:0, prevX: prevX, prevY: prevY, prevZ: prevZ, speed: lastF, gcodeLine: i};
if(typeof(x) !== 'undefined') prevX = x;
if(typeof(y) !== 'undefined') prevY = y;
} else if(line.match(/^(?:M82)/i)){
extrudeRelative = false;
}else if(line.match(/^(?:G91)/i)){
extrudeRelative=true;
}else if(line.match(/^(?:G90)/i)){
extrudeRelative=false;
}else if(line.match(/^(?:M83)/i)){
extrudeRelative=true;
}else if(line.match(/^(?:M101)/i)){
dcExtrude=true;
}else if(line.match(/^(?:M103)/i)){
dcExtrude=false;
}else if(line.match(/^(?:G92)/i)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
prevZ = z;
break;
case 'e'||'a'||'b'||'c':
numSlice = args[j].slice(1);
if(!extrudeRelative)
prev_extrude[argChar] = 0;
else {
prev_extrude[argChar] = numSlice;
}
break;
default:
break;
}
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined') model[layer][model[layer].length] = {x: parseFloat(x), y: parseFloat(y), z: parseFloat(z), extrude: extrude, retract: parseFloat(retract), noMove: true, extrusion: (extrude||retract)?parseFloat(prev_extrude["abs"]):0, prevX: parseFloat(prevX), prevY: parseFloat(prevY), prevZ: parseFloat(prevZ), speed: parseFloat(lastF),gcodeLine: parseFloat(i), percentage: percentage};
}else if(line.match(/^(?:G28)/i)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
z = Number(z);
if(z === prevZ)continue;
sendLayer = layer;
sendLayerZ = z;//}
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
prevZ = z;
break;
default:
break;
}
}
// G28 with no arguments
if(args.length == 1){
//need to init values to default here
}
// if it's the first layer and G28 was without
if(layer==0&&typeof(z) === 'undefined'){
z=0;
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
prevZ = z;
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i), percentage: percentage};
}
if(typeof(sendLayer) !== "undefined"){
if(i-lastSend > gcode.length*0.02 && sendMultiLayer.length != 0){
lastSend = i;
sendMultiLayerToParent(sendMultiLayer, sendMultiLayerZ, i/gcode.length*100);
sendMultiLayer = [];
sendMultiLayerZ = [];
}
sendMultiLayer[sendMultiLayer.length] = sendLayer;
sendMultiLayerZ[sendMultiLayerZ.length] = sendLayerZ;
sendLayer = undefined;
sendLayerZ = undefined;
}
}
sendMultiLayerToParent(sendMultiLayer, sendMultiLayerZ, i/gcode.length*100);
};
var parseGCode = function(message){
gcode = message.gcode;
firstReport = message.options.firstReport;
doParse();
gcode = [];
self.postMessage({
"cmd": "returnModel",
"msg": {
// model: model
}
});
};
var runAnalyze = function(message){
analyzeModel();
model = [];
z_heights = [];
gcode = undefined;
firstReport = undefined;
z_heights = {};
model = [];
max = {x: undefined, y: undefined, z: undefined};
min = {x: undefined, y: undefined, z: undefined};
modelSize = {x: undefined, y: undefined, z: undefined};
filamentByLayer = {};
totalFilament=0;
printTime=0;
printTimeByLayer = {};
layerHeight=0;
layerCnt = 0;
speeds = {extrude: [], retract: [], move: []};
speedsByLayer = {extrude: {}, retract: {}, move: {}};
};
var setOption = function(options){
for(var opt in options){
gCodeOptions[opt] = options[opt];
}
};
onmessage = function (e){
var data = e.data;
// for some reason firefox doesn't garbage collect when something inside closures is deleted, so we delete and recreate whole object eaech time
switch (data.cmd) {
case 'parseGCode':
parseGCode(data.msg);
break;
case 'setOption':
setOption(data.msg);
break;
case 'analyzeModel':
runAnalyze(data.msg);
break;
default:
self.postMessage('Unknown command: ' + data.msg);
}
};
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/24/12
* Time: 12:18 PM
*/
var gcode;
var firstReport;
var z_heights = {};
var model = [];
var gCodeOptions = {
sortLayers: false,
purgeEmptyLayers: true,
analyzeModel: false
};
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var filamentByLayer = {};
var totalFilament=0;
var printTime=0;
var printTimeByLayer = {};
var layerHeight=0;
var layerCnt = 0;
var speeds = {extrude: [], retract: [], move: []};
var speedsByLayer = {extrude: {}, retract: {}, move: {}};
var sendLayerToParent = function(layerNum, z, progress){
self.postMessage({
"cmd": "returnLayer",
"msg": {
cmds: model[layerNum],
layerNum: layerNum,
zHeightObject: {zValue: z, layer: z_heights[z]},
isEmpty: false,
progress: progress
}
});
};
var sendMultiLayerToParent = function(layerNum, z, progress){
var tmpModel = [];
var tmpZHeight = {};
for(var i=0;i<layerNum.length;i++){
tmpModel[layerNum[i]] = model[layerNum[i]];
tmpZHeight[layerNum[i]] = z_heights[z[i]];
}
self.postMessage({
"cmd": "returnMultiLayer",
"msg": {
model: tmpModel,
layerNum: layerNum,
zHeightObject: {zValue: z, layer: tmpZHeight},
isEmpty: false,
progress: progress
}
});
};
var sendSizeProgress = function(progress){
self.postMessage({
"cmd": "analyzeProgress",
"msg": {
progress: progress,
printTime: printTime
}
});
};
var sendAnalyzeDone = function(){
self.postMessage({
"cmd": "analyzeDone",
"msg": {
max: max,
min: min,
modelSize: modelSize,
totalFilament:totalFilament,
filamentByLayer: filamentByLayer,
printTime: printTime,
layerHeight: layerHeight,
layerCnt: layerCnt,
layerTotal: model.length,
speeds: speeds,
speedsByLayer: speedsByLayer,
printTimeByLayer: printTimeByLayer
}
});
};
var purgeLayers = function(){
var purge=true;
for(var i=0;i<model.length;i++){
purge=true;
if(!model[i])purge=true;
else {
for(var j=0;j<model[i].length;j++){
if(model[i][j].extrude)purge=false;
}
}
if(!purge){
layerCnt+=1;
}
}
// self.postMessage('LayerCnt: ' + layerCnt);
};
var analyzeModel = function(){
var i,j;
var x_ok=false, y_ok=false;
var cmds;
var tmp1= 0, tmp2=0;
var speedIndex=0;
var type;
var printTimeAdd=0;
// var moveTime=0;
for(i=0;i<model.length;i++){
cmds = model[i];
if(!cmds)continue;
for(j=0;j<cmds.length;j++){
x_ok=false;
y_ok=false;
if(typeof(cmds[j].x) !== 'undefined'&&typeof(cmds[j].prevX) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].x))
{
max.x = parseFloat(max.x)>parseFloat(cmds[j].x)?parseFloat(max.x):parseFloat(cmds[j].x);
max.x = parseFloat(max.x)>parseFloat(cmds[j].prevX)?parseFloat(max.x):parseFloat(cmds[j].prevX);
min.x = parseFloat(min.x)<parseFloat(cmds[j].x)?parseFloat(min.x):parseFloat(cmds[j].x);
min.x = parseFloat(min.x)<parseFloat(cmds[j].prevX)?parseFloat(min.x):parseFloat(cmds[j].prevX);
x_ok=true;
}
if(typeof(cmds[j].y) !== 'undefined'&&typeof(cmds[j].prevY) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].y)){
max.y = parseFloat(max.y)>parseFloat(cmds[j].y)?parseFloat(max.y):parseFloat(cmds[j].y);
max.y = parseFloat(max.y)>parseFloat(cmds[j].prevY)?parseFloat(max.y):parseFloat(cmds[j].prevY);
min.y = parseFloat(min.y)<parseFloat(cmds[j].y)?parseFloat(min.y):parseFloat(cmds[j].y);
min.y = parseFloat(min.y)<parseFloat(cmds[j].prevY)?parseFloat(min.y):parseFloat(cmds[j].prevY);
y_ok=true;
}
if(typeof(cmds[j].prevZ) !== 'undefined'&&typeof(cmds[j].extrude) !== 'undefined'&&cmds[j].extrude&&!isNaN(cmds[j].prevZ)){
max.z = parseFloat(max.z)>parseFloat(cmds[j].prevZ)?parseFloat(max.z):parseFloat(cmds[j].prevZ);
min.z = parseFloat(min.z)<parseFloat(cmds[j].prevZ)?parseFloat(min.z):parseFloat(cmds[j].prevZ);
}
if(typeof(cmds[j].extrude) !== 'undefined'||cmds[j].retract!=0){
totalFilament+=cmds[j].extrusion;
if(!filamentByLayer[cmds[j].prevZ])filamentByLayer[cmds[j].prevZ]=0;
filamentByLayer[cmds[j].prevZ]+=cmds[j].extrusion;
}
if(x_ok&&y_ok){
printTimeAdd = Math.sqrt(Math.pow(parseFloat(cmds[j].x)-parseFloat(cmds[j].prevX),2)+Math.pow(parseFloat(cmds[j].y)-parseFloat(cmds[j].prevY),2))/(cmds[j].speed/60);
}else if(cmds[j].retract===0&&cmds[j].extrusion!==0){
tmp1 = Math.sqrt(Math.pow(parseFloat(cmds[j].x)-parseFloat(cmds[j].prevX),2)+Math.pow(parseFloat(cmds[j].y)-parseFloat(cmds[j].prevY),2))/(cmds[j].speed/60);
tmp2 = Math.abs(parseFloat(cmds[j].extrusion)/(cmds[j].speed/60));
printTimeAdd = tmp1>=tmp2?tmp1:tmp2;
}else if(cmds[j].retract!==0){
printTimeAdd = Math.abs(parseFloat(cmds[j].extrusion)/(cmds[j].speed/60));
}
printTime += printTimeAdd;
if(typeof(printTimeByLayer[cmds[j].prevZ])==='undefined'){printTimeByLayer[cmds[j].prevZ]=0;}
printTimeByLayer[cmds[j].prevZ] += printTimeAdd;
if(cmds[j].extrude&&cmds[j].retract===0){
type = 'extrude';
}else if(cmds[j].retract!==0){
type = 'retract';
}else if(!cmds[j].extrude&&cmds[j].retract===0){
type = 'move';
// if(cmds[j].prevZ == '17.1'){
// self.postMessage({cmd: 'Got speed ' + cmds[j].speed + 'with line ' + cmds[j].gcodeLine});
// }
}else {
self.postMessage({cmd: 'unknown type of move'});
type = 'unknown';
}
speedIndex = speeds[type].indexOf(cmds[j].speed);
if (speedIndex === -1) {
speeds[type].push(cmds[j].speed);
speedIndex = speeds[type].indexOf(cmds[j].speed);
}
if(typeof(speedsByLayer[type][cmds[j].prevZ]) === 'undefined'){
speedsByLayer[type][cmds[j].prevZ] = [];
}
if(speedsByLayer[type][cmds[j].prevZ].indexOf(cmds[j].speed) === -1){
speedsByLayer[type][cmds[j].prevZ][speedIndex] = cmds[j].speed;
}
}
sendSizeProgress(i/model.length*100);
}
purgeLayers();
modelSize.x = Math.abs(max.x - min.x);
modelSize.y = Math.abs(max.y - min.y);
modelSize.z = Math.abs(max.z - min.z);
layerHeight = (max.z-min.z)/(layerCnt-1);
sendAnalyzeDone();
};
var doParse = function(){
var argChar, numSlice;
model=[];
var sendLayer = undefined;
var sendLayerZ = 0;
var sendMultiLayer = [];
var sendMultiLayerZ = [];
var lastSend = 0;
// console.time("parseGCode timer");
var reg = new RegExp(/^(?:G0|G1)\s/i);
var comment = new RegExp()
var j, layer= 0, extrude=false, prevRetract= 0, retract=0, x, y, z=0, f, prevZ=0, prevX, prevY,lastF=4000, prev_extrude = {a: undefined, b: undefined, c: undefined, e: undefined, abs: undefined}, extrudeRelative=false;
var dcExtrude=false;
var assumeNonDC = false;
for(var i=0;i<gcode.length;i++){
x=undefined;
y=undefined;
z=undefined;
retract = 0;
var line = gcode[i].line;
var percentage = gcode[i].percentage;
extrude=false;
line = line.split(/[\(;]/)[0];
if(reg.test(line)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
z = Number(z);
if(z == prevZ) continue;
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
sendLayer = layer;
sendLayerZ = z;
prevZ = z;
break;
case 'e':
case 'a':
case 'b':
case 'c':
assumeNonDC = true;
numSlice = parseFloat(args[j].slice(1)).toFixed(3);
if(!extrudeRelative){
// absolute extrusion positioning
prev_extrude["abs"] = parseFloat(numSlice)-parseFloat(prev_extrude[argChar]);
}else{
prev_extrude["abs"] = parseFloat(numSlice);
}
extrude = prev_extrude["abs"]>0;
if(prev_extrude["abs"]<0){
prevRetract = -1;
retract = -1;
}
else if(prev_extrude["abs"]==0){
retract = 0;
}else if(prev_extrude["abs"]>0&&prevRetract < 0){
prevRetract = 0;
retract = 1;
} else {
retract = 0;
}
prev_extrude[argChar] = numSlice;
break;
case 'f':
numSlice = args[j].slice(1);
lastF = numSlice;
break;
default:
break;
}
}
if(dcExtrude&&!assumeNonDC){
extrude = true;
prev_extrude["abs"] = Math.sqrt((prevX-x)*(prevX-x)+(prevY-y)*(prevY-y));
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i), percentage: percentage};
//{x: x, y: y, z: z, extrude: extrude, retract: retract, noMove: false, extrusion: (extrude||retract)?prev_extrude["abs"]:0, prevX: prevX, prevY: prevY, prevZ: prevZ, speed: lastF, gcodeLine: i};
if(typeof(x) !== 'undefined') prevX = x;
if(typeof(y) !== 'undefined') prevY = y;
} else if(line.match(/^(?:M82)/i)){
extrudeRelative = false;
}else if(line.match(/^(?:G91)/i)){
extrudeRelative=true;
}else if(line.match(/^(?:G90)/i)){
extrudeRelative=false;
}else if(line.match(/^(?:M83)/i)){
extrudeRelative=true;
}else if(line.match(/^(?:M101)/i)){
dcExtrude=true;
}else if(line.match(/^(?:M103)/i)){
dcExtrude=false;
}else if(line.match(/^(?:G92)/i)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
prevZ = z;
break;
case 'e'||'a'||'b'||'c':
numSlice = args[j].slice(1);
if(!extrudeRelative)
prev_extrude[argChar] = 0;
else {
prev_extrude[argChar] = numSlice;
}
break;
default:
break;
}
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined') model[layer][model[layer].length] = {x: parseFloat(x), y: parseFloat(y), z: parseFloat(z), extrude: extrude, retract: parseFloat(retract), noMove: true, extrusion: (extrude||retract)?parseFloat(prev_extrude["abs"]):0, prevX: parseFloat(prevX), prevY: parseFloat(prevY), prevZ: parseFloat(prevZ), speed: parseFloat(lastF),gcodeLine: parseFloat(i), percentage: percentage};
}else if(line.match(/^(?:G28)/i)){
var args = line.split(/\s/);
for(j=0;j<args.length;j++){
switch(argChar = args[j].charAt(0).toLowerCase()){
case 'x':
x=args[j].slice(1);
break;
case 'y':
y=args[j].slice(1);
break;
case 'z':
z=args[j].slice(1);
z = Number(z);
if(z === prevZ)continue;
sendLayer = layer;
sendLayerZ = z;//}
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
prevZ = z;
break;
default:
break;
}
}
// G28 with no arguments
if(args.length == 1){
//need to init values to default here
}
// if it's the first layer and G28 was without
if(layer==0&&typeof(z) === 'undefined'){
z=0;
if(z_heights.hasOwnProperty(z)){
layer = z_heights[z];
}else{
layer = model.length;
z_heights[z] = layer;
}
prevZ = z;
}
if(!model[layer])model[layer]=[];
if(typeof(x) !== 'undefined' || typeof(y) !== 'undefined' ||typeof(z) !== 'undefined'||retract!=0) model[layer][model[layer].length] = {x: Number(x), y: Number(y), z: Number(z), extrude: extrude, retract: Number(retract), noMove: false, extrusion: (extrude||retract)?Number(prev_extrude["abs"]):0, prevX: Number(prevX), prevY: Number(prevY), prevZ: Number(prevZ), speed: Number(lastF), gcodeLine: Number(i), percentage: percentage};
}
if(typeof(sendLayer) !== "undefined"){
if(i-lastSend > gcode.length*0.02 && sendMultiLayer.length != 0){
lastSend = i;
sendMultiLayerToParent(sendMultiLayer, sendMultiLayerZ, i/gcode.length*100);
sendMultiLayer = [];
sendMultiLayerZ = [];
}
sendMultiLayer[sendMultiLayer.length] = sendLayer;
sendMultiLayerZ[sendMultiLayerZ.length] = sendLayerZ;
sendLayer = undefined;
sendLayerZ = undefined;
}
}
sendMultiLayerToParent(sendMultiLayer, sendMultiLayerZ, i/gcode.length*100);
};
var parseGCode = function(message){
gcode = message.gcode;
firstReport = message.options.firstReport;
doParse();
gcode = [];
self.postMessage({
"cmd": "returnModel",
"msg": {
// model: model
}
});
};
var runAnalyze = function(message){
analyzeModel();
model = [];
z_heights = [];
gcode = undefined;
firstReport = undefined;
z_heights = {};
model = [];
max = {x: undefined, y: undefined, z: undefined};
min = {x: undefined, y: undefined, z: undefined};
modelSize = {x: undefined, y: undefined, z: undefined};
filamentByLayer = {};
totalFilament=0;
printTime=0;
printTimeByLayer = {};
layerHeight=0;
layerCnt = 0;
speeds = {extrude: [], retract: [], move: []};
speedsByLayer = {extrude: {}, retract: {}, move: {}};
};
var setOption = function(options){
for(var opt in options){
gCodeOptions[opt] = options[opt];
}
};
onmessage = function (e){
var data = e.data;
// for some reason firefox doesn't garbage collect when something inside closures is deleted, so we delete and recreate whole object eaech time
switch (data.cmd) {
case 'parseGCode':
parseGCode(data.msg);
break;
case 'setOption':
setOption(data.msg);
break;
case 'analyzeModel':
runAnalyze(data.msg);
break;
default:
self.postMessage('Unknown command: ' + data.msg);
}
};

View file

@ -1,207 +1,207 @@
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/21/12
* Time: 7:31 AM
*/
GCODE.gCodeReader = (function(){
// ***** PRIVATE ******
var gcode, lines;
var z_heights = {};
var model = [];
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var filamentByLayer = {};
var printTimeByLayer;
var totalFilament=0;
var printTime=0;
var speeds = {};
var speedsByLayer = {};
var gCodeOptions = {
sortLayers: false,
purgeEmptyLayers: true,
analyzeModel: false
};
var percentageTree = undefined;
var prepareGCode = function(totalSize){
if(!lines)return;
gcode = [];
var i, tmp, byteCount;
byteCount = 0;
for(i=0;i<lines.length;i++){
byteCount += lines[i].length + 1; // line length + \n
tmp = lines[i].indexOf(";");
if(tmp > 1 || tmp === -1) {
gcode.push({line: lines[i], percentage: byteCount * 100 / totalSize});
}
}
lines = [];
};
var sortLayers = function(){
var sortedZ = [];
var tmpModel = [];
for(var layer in z_heights){
sortedZ[z_heights[layer]] = layer;
}
sortedZ.sort(function(a,b){
return a-b;
});
for(var i=0;i<sortedZ.length;i++){
if(typeof(z_heights[sortedZ[i]]) === 'undefined')continue;
tmpModel[i] = model[z_heights[sortedZ[i]]];
}
model = tmpModel;
delete tmpModel;
};
var prepareLinesIndex = function(){
percentageTree = undefined;
for (var l in model) {
for (var i=0; i< model[l].length; i++) {
var percentage = model[l][i].percentage;
var value = {layer: l, cmd: i};
if (!percentageTree) {
percentageTree = new AVLTree({key: percentage, value: value}, "key");
} else {
percentageTree.add({key: percentage, value: value});
}
}
}
};
var searchInPercentageTree = function(key) {
if (percentageTree === undefined) {
return undefined;
}
var elements = percentageTree.findBest(key);
if (elements.length == 0) {
return undefined;
}
return elements[0];
};
var purgeLayers = function(){
var purge=true;
if(!model){
console.log("Something terribly wring just happened.");
return;
}
for(var i=0;i<model.length;i++){
purge=true;
if(typeof(model[i])==='undefined')purge=true;
else {
for(var j=0;j<model[i].length;j++){
if(model[i][j].extrude)purge=false;
}
}
if(purge){
model.splice(i,1);
i--;
}
}
};
// ***** PUBLIC *******
return {
loadFile: function(reader){
model = [];
z_heights = [];
var totalSize = reader.target.result.length;
lines = reader.target.result.split(/\n/);
reader.target.result = null;
prepareGCode(totalSize);
worker.postMessage({
"cmd":"parseGCode",
"msg":{
gcode: gcode,
options: {
firstReport: 5
}
}
}
);
delete lines;
delete gcode;
},
setOption: function(options){
for(var opt in options){
gCodeOptions[opt] = options[opt];
}
},
passDataToRenderer: function(){
if(gCodeOptions["sortLayers"])sortLayers();
if(gCodeOptions["purgeEmptyLayers"])purgeLayers();
prepareLinesIndex();
GCODE.renderer.doRender(model, 0);
},
processLayerFromWorker: function(msg){
model[msg.layerNum] = msg.cmds;
z_heights[msg.zHeightObject.zValue] = msg.zHeightObject.layer;
},
processMultiLayerFromWorker: function(msg){
for(var i=0;i<msg.layerNum.length;i++){
model[msg.layerNum[i]] = msg.model[msg.layerNum[i]];
z_heights[msg.zHeightObject.zValue[i]] = msg.layerNum[i];
}
},
processAnalyzeModelDone: function(msg){
min = msg.min;
max = msg.max;
modelSize = msg.modelSize;
totalFilament = msg.totalFilament;
filamentByLayer = msg.filamentByLayer;
speeds = msg.speeds;
speedsByLayer = msg.speedsByLayer;
printTime = msg.printTime;
printTimeByLayer = msg.printTimeByLayer;
},
getLayerFilament: function(z){
return filamentByLayer[z];
},
getLayerSpeeds: function(z){
return speedsByLayer[z]?speedsByLayer[z]:{};
},
getModelInfo: function(){
return {
min: min,
max: max,
modelSize: modelSize,
totalFilament: totalFilament,
speeds: speeds,
speedsByLayer: speedsByLayer,
printTime: printTime,
printTimeByLayer: printTimeByLayer
};
},
getGCodeLines: function(layer, fromSegments, toSegments){
var i=0;
var result = {first: model[layer][fromSegments].gcodeLine, last: model[layer][toSegments].gcodeLine};
return result;
},
getCmdIndexForPercentage: function(percentage) {
var command = searchInPercentageTree(percentage);
if (command === undefined) {
return undefined
} else {
return command.value;
}
}
}
}());
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/21/12
* Time: 7:31 AM
*/
GCODE.gCodeReader = (function(){
// ***** PRIVATE ******
var gcode, lines;
var z_heights = {};
var model = [];
var max = {x: undefined, y: undefined, z: undefined};
var min = {x: undefined, y: undefined, z: undefined};
var modelSize = {x: undefined, y: undefined, z: undefined};
var filamentByLayer = {};
var printTimeByLayer;
var totalFilament=0;
var printTime=0;
var speeds = {};
var speedsByLayer = {};
var gCodeOptions = {
sortLayers: false,
purgeEmptyLayers: true,
analyzeModel: false
};
var percentageTree = undefined;
var prepareGCode = function(totalSize){
if(!lines)return;
gcode = [];
var i, tmp, byteCount;
byteCount = 0;
for(i=0;i<lines.length;i++){
byteCount += lines[i].length + 1; // line length + \n
tmp = lines[i].indexOf(";");
if(tmp > 1 || tmp === -1) {
gcode.push({line: lines[i], percentage: byteCount * 100 / totalSize});
}
}
lines = [];
};
var sortLayers = function(){
var sortedZ = [];
var tmpModel = [];
for(var layer in z_heights){
sortedZ[z_heights[layer]] = layer;
}
sortedZ.sort(function(a,b){
return a-b;
});
for(var i=0;i<sortedZ.length;i++){
if(typeof(z_heights[sortedZ[i]]) === 'undefined')continue;
tmpModel[i] = model[z_heights[sortedZ[i]]];
}
model = tmpModel;
delete tmpModel;
};
var prepareLinesIndex = function(){
percentageTree = undefined;
for (var l in model) {
for (var i=0; i< model[l].length; i++) {
var percentage = model[l][i].percentage;
var value = {layer: l, cmd: i};
if (!percentageTree) {
percentageTree = new AVLTree({key: percentage, value: value}, "key");
} else {
percentageTree.add({key: percentage, value: value});
}
}
}
};
var searchInPercentageTree = function(key) {
if (percentageTree === undefined) {
return undefined;
}
var elements = percentageTree.findBest(key);
if (elements.length == 0) {
return undefined;
}
return elements[0];
};
var purgeLayers = function(){
var purge=true;
if(!model){
console.log("Something terribly wring just happened.");
return;
}
for(var i=0;i<model.length;i++){
purge=true;
if(typeof(model[i])==='undefined')purge=true;
else {
for(var j=0;j<model[i].length;j++){
if(model[i][j].extrude)purge=false;
}
}
if(purge){
model.splice(i,1);
i--;
}
}
};
// ***** PUBLIC *******
return {
loadFile: function(reader){
model = [];
z_heights = [];
var totalSize = reader.target.result.length;
lines = reader.target.result.split(/\n/);
reader.target.result = null;
prepareGCode(totalSize);
worker.postMessage({
"cmd":"parseGCode",
"msg":{
gcode: gcode,
options: {
firstReport: 5
}
}
}
);
delete lines;
delete gcode;
},
setOption: function(options){
for(var opt in options){
gCodeOptions[opt] = options[opt];
}
},
passDataToRenderer: function(){
if(gCodeOptions["sortLayers"])sortLayers();
if(gCodeOptions["purgeEmptyLayers"])purgeLayers();
prepareLinesIndex();
GCODE.renderer.doRender(model, 0);
},
processLayerFromWorker: function(msg){
model[msg.layerNum] = msg.cmds;
z_heights[msg.zHeightObject.zValue] = msg.zHeightObject.layer;
},
processMultiLayerFromWorker: function(msg){
for(var i=0;i<msg.layerNum.length;i++){
model[msg.layerNum[i]] = msg.model[msg.layerNum[i]];
z_heights[msg.zHeightObject.zValue[i]] = msg.layerNum[i];
}
},
processAnalyzeModelDone: function(msg){
min = msg.min;
max = msg.max;
modelSize = msg.modelSize;
totalFilament = msg.totalFilament;
filamentByLayer = msg.filamentByLayer;
speeds = msg.speeds;
speedsByLayer = msg.speedsByLayer;
printTime = msg.printTime;
printTimeByLayer = msg.printTimeByLayer;
},
getLayerFilament: function(z){
return filamentByLayer[z];
},
getLayerSpeeds: function(z){
return speedsByLayer[z]?speedsByLayer[z]:{};
},
getModelInfo: function(){
return {
min: min,
max: max,
modelSize: modelSize,
totalFilament: totalFilament,
speeds: speeds,
speedsByLayer: speedsByLayer,
printTime: printTime,
printTimeByLayer: printTimeByLayer
};
},
getGCodeLines: function(layer, fromSegments, toSegments){
var i=0;
var result = {first: model[layer][fromSegments].gcodeLine, last: model[layer][toSegments].gcodeLine};
return result;
},
getCmdIndexForPercentage: function(percentage) {
var command = searchInPercentageTree(percentage);
if (command === undefined) {
return undefined
} else {
return command.value;
}
}
}
}());

View file

@ -1,417 +1,417 @@
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/20/12
* Time: 1:36 PM
* To change this template use File | Settings | File Templates.
*/
GCODE.renderer = (function(){
// ***** PRIVATE ******
var canvas;
var ctx;
var zoomFactor= 2.8, zoomFactorDelta = 0.4;
var gridSizeX=200,gridSizeY=200,gridStep=10;
var ctxHeight, ctxWidth;
var prevX=0, prevY=0;
// var colorGrid="#bbbbbb", colorLine="#000000";
var sliderHor, sliderVer;
var layerNumStore, progressStore={from: 0, to: -1};
var lastX, lastY;
var dragStart,dragged;
var scaleFactor = 1.1;
var model;
var initialized=false;
var renderOptions = {
showMoves: true,
showRetracts: true,
colorGrid: "#bbbbbb",
extrusionWidth: 1,
// colorLine: ["#000000", "#aabb88", "#ffe7a0", "#6e7700", "#331a00", "#44ba97", "#08262f", "#db0e00", "#ff9977"],
colorLine: ["#000000", "#45c7ba", "#a9533a", "#ff44cc", "#dd1177", "#eeee22", "#ffbb55", "#ff5511", "#777788"],
colorMove: "#00ff00",
colorRetract: "#ff0000",
colorRestart: "#0000ff",
sizeRetractSpot: 2,
modelCenter: {x: 0, y: 0},
moveModel: true,
differentiateColors: true,
showNextLayer: false
};
var offsetModelX=0, offsetModelY=0;
var speeds = [];
var speedsByLayer = {};
var reRender = function(){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
drawGrid();
if(renderOptions['showNextLayer'] && layerNumStore < model.length - 1) {
drawLayer(layerNumStore+1, 0, GCODE.renderer.getLayerNumSegments(layerNumStore+1), true);
}
drawLayer(layerNumStore, progressStore.from, progressStore.to);
};
function trackTransforms(ctx){
var svg = document.createElementNS("http://www.w3.org/2000/svg",'svg');
var xform = svg.createSVGMatrix();
ctx.getTransform = function(){ return xform; };
var savedTransforms = [];
var save = ctx.save;
ctx.save = function(){
savedTransforms.push(xform.translate(0,0));
return save.call(ctx);
};
var restore = ctx.restore;
ctx.restore = function(){
xform = savedTransforms.pop();
return restore.call(ctx);
};
var scale = ctx.scale;
ctx.scale = function(sx,sy){
xform = xform.scaleNonUniform(sx,sy);
return scale.call(ctx,sx,sy);
};
var rotate = ctx.rotate;
ctx.rotate = function(radians){
xform = xform.rotate(radians*180/Math.PI);
return rotate.call(ctx,radians);
};
var translate = ctx.translate;
ctx.translate = function(dx,dy){
xform = xform.translate(dx,dy);
return translate.call(ctx,dx,dy);
};
var transform = ctx.transform;
ctx.transform = function(a,b,c,d,e,f){
var m2 = svg.createSVGMatrix();
m2.a=a; m2.b=b; m2.c=c; m2.d=d; m2.e=e; m2.f=f;
xform = xform.multiply(m2);
return transform.call(ctx,a,b,c,d,e,f);
};
var setTransform = ctx.setTransform;
ctx.setTransform = function(a,b,c,d,e,f){
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx,a,b,c,d,e,f);
};
var pt = svg.createSVGPoint();
ctx.transformedPoint = function(x,y){
pt.x=x; pt.y=y;
return pt.matrixTransform(xform.inverse());
}
}
var startCanvas = function() {
canvas = document.getElementById('canvas');
// Проверяем понимает ли браузер canvas
if (!canvas.getContext) {
throw "exception";
}
ctx = canvas.getContext('2d'); // Получаем 2D контекст
ctxHeight = canvas.height;
ctxWidth = canvas.width;
lastX = ctxWidth/2;
lastY = ctxHeight/2;
ctx.lineWidth = 2;
ctx.lineCap = 'round';
trackTransforms(ctx);
canvas.addEventListener('mousedown',function(evt){
document.body.style.mozUserSelect = document.body.style.webkitUserSelect = document.body.style.userSelect = 'none';
lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
dragStart = ctx.transformedPoint(lastX,lastY);
dragged = false;
},false);
canvas.addEventListener('mousemove',function(evt){
lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
dragged = true;
if (dragStart){
var pt = ctx.transformedPoint(lastX,lastY);
ctx.translate(pt.x-dragStart.x,pt.y-dragStart.y);
reRender();
}
},false);
canvas.addEventListener('mouseup',function(evt){
dragStart = null;
if (!dragged) zoom(evt.shiftKey ? -1 : 1 );
},false);
var zoom = function(clicks){
var pt = ctx.transformedPoint(lastX,lastY);
ctx.translate(pt.x,pt.y);
var factor = Math.pow(scaleFactor,clicks);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
reRender();
};
var handleScroll = function(evt){
var delta;
if(evt.detail<0 || evt.wheelDelta>0)delta=zoomFactorDelta;
else delta=-1*zoomFactorDelta;
if (delta) zoom(delta);
return evt.preventDefault() && false;
};
canvas.addEventListener('DOMMouseScroll',handleScroll,false);
canvas.addEventListener('mousewheel',handleScroll,false);
};
var drawGrid = function() {
var i;
ctx.strokeStyle = renderOptions["colorGrid"];
ctx.lineWidth = 1;
var offsetX=0, offsetY=0;
if(renderOptions["moveModel"]){
offsetX = offsetModelX;
offsetY = offsetModelY;
}
ctx.beginPath();
for(i=0;i<=gridSizeX;i+=gridStep){
ctx.moveTo(i*zoomFactor-offsetX, 0-offsetY);
ctx.lineTo(i*zoomFactor-offsetX, -gridSizeY*zoomFactor-offsetY);
}
ctx.stroke();
ctx.beginPath();
for(i=0;i<=gridSizeY;i+=gridStep){
ctx.moveTo(0-offsetX, -i*zoomFactor-offsetY);
ctx.lineTo(gridSizeX*zoomFactor-offsetX, -i*zoomFactor-offsetY);
}
ctx.stroke();
};
var drawLayer = function(layerNum, fromProgress, toProgress, isNextLayer){
var i, speedIndex= 0, prevZ = 0;
isNextLayer = typeof isNextLayer !== 'undefined' ? isNextLayer : false;
if(!isNextLayer){
layerNumStore=layerNum;
progressStore = {from: fromProgress, to: toProgress};
}
if(!model||!model[layerNum])return;
var cmds = model[layerNum];
var x, y;
// if(toProgress === -1){
// toProgress=cmds.length;
// }
if(fromProgress>0){
prevX = cmds[fromProgress-1].x*zoomFactor;
prevY = -cmds[fromProgress-1].y*zoomFactor;
}else if(fromProgress===0 && layerNum==0){
if(model[0]&&model[0].x !== undefined &&model[0].y !== undefined){
prevX = model[0].x*zoomFactor;
prevY = -model[0].y*zoomFactor;
}else {
prevX = 0;
prevY = 0;
}
}else if(typeof(cmds[0].prevX) !== 'undefined' && typeof(cmds[0].prevY) !== 'undefined'){
prevX = cmds[0].prevX*zoomFactor;
prevY = -cmds[0].prevY*zoomFactor;
}else{
if(model[layerNum-1]){
prevX=undefined;
prevY=undefined;
for(i=model[layerNum-1].length-1;i>=0;i--){
if(prevX === undefined && model[layerNum-1][i].x!==undefined)prevX=model[layerNum-1][i].x*zoomFactor;
if(prevY === undefined && model[layerNum-1][i].y!==undefined)prevY=-model[layerNum-1][i].y*zoomFactor;
}
if(prevX === undefined)prevX=0;
if(prevY === undefined)prevY=0;
}else{
prevX=0;
prevY=0;
}
}
prevZ = GCODE.renderer.getZ(layerNum);
// ctx.strokeStyle = renderOptions["colorLine"];
for(i=fromProgress;i<=toProgress;i++){
ctx.lineWidth = 1;
if(typeof(cmds[i]) === 'undefined')continue;
if(typeof(cmds[i].prevX) !== 'undefined' && typeof(cmds[i].prevY) !== 'undefined'){
prevX = cmds[i].prevX*zoomFactor;
prevY = -cmds[i].prevY*zoomFactor;
}
// console.log(cmds[i]);
if(typeof(cmds[i].x)==='undefined'||isNaN(cmds[i].x))x=prevX/zoomFactor;
else x = cmds[i].x;
if(typeof(cmds[i].y) === 'undefined'||isNaN(cmds[i].y))y=prevY/zoomFactor;
else y = -cmds[i].y;
if(renderOptions["differentiateColors"]&&!renderOptions['showNextLayer']){
// if(speedsByLayer['extrude'][prevZ]){
speedIndex = speeds['extrude'].indexOf(cmds[i].speed);
// speedIndex = GCODE.ui.ArrayIndexOf(speedsByLayer['extrude'][prevZ], function(obj) {return obj.speed === cmds[i].speed;});
// } else {
// speedIndex = -1;
// }
if(speedIndex === -1){
speedIndex = 0;
}else if(speedIndex > renderOptions["colorLine"].length -1){
speedIndex = speedIndex % (renderOptions["colorLine"].length-1);
// console.log("Too much colors");
}
}else if(renderOptions['showNextLayer']&&isNextLayer){
speedIndex=3;
}else{
speedIndex=0;
}
if(!cmds[i].extrude&&!cmds[i].noMove){
// ctx.stroke();
if(cmds[i].retract == -1){
if(renderOptions["showRetracts"]){
ctx.strokeStyle = renderOptions["colorRetract"];
ctx.fillStyle = renderOptions["colorRetract"];
ctx.beginPath();
ctx.arc(prevX, prevY, renderOptions["sizeRetractSpot"], 0, Math.PI*2, true);
ctx.stroke();
ctx.fill();
}
}
if(renderOptions["showMoves"]){
ctx.strokeStyle = renderOptions["colorMove"];
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x*zoomFactor,y*zoomFactor);
ctx.stroke();
}
// ctx.strokeStyle = renderOptions["colorLine"][0];
// ctx.beginPath();
// console.log("moveto: "+cmds[i].x+":"+cmds[i].y)
// ctx.moveTo(cmds[i].x*zoomFactor,cmds[i].y*zoomFactor);
}
else if(cmds[i].extrude){
if(cmds[i].retract==0){
ctx.strokeStyle = renderOptions["colorLine"][speedIndex];
ctx.lineWidth = renderOptions['extrusionWidth'];
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x*zoomFactor,y*zoomFactor);
ctx.stroke();
}else {
if(renderOptions["showRetracts"]){
// ctx.stroke();
ctx.strokeStyle = renderOptions["colorRestart"];
ctx.fillStyle = renderOptions["colorRestart"];
ctx.beginPath();
ctx.arc(prevX, prevY, renderOptions["sizeRetractSpot"], 0, Math.PI*2, true);
ctx.stroke();
ctx.fill();
// ctx.strokeStyle = renderOptions["colorLine"][0];
// ctx.beginPath();
}
}
}
prevX = x*zoomFactor;
prevY = y*zoomFactor;
}
ctx.stroke();
};
// ***** PUBLIC *******
return {
init: function(){
startCanvas();
initialized = true;
ctx.translate(10,gridSizeY*zoomFactor+20);
},
setOption: function(options){
for(var opt in options){
if(options.hasOwnProperty(opt))renderOptions[opt] = options[opt];
};
if(initialized)reRender();
},
getOptions: function(){
return renderOptions;
},
debugGetModel: function(){
return model;
},
render: function(layerNum, fromProgress, toProgress){
if(!initialized)this.init();
if(!model){
drawGrid();
}else{
if(layerNum < model.length){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
drawGrid();
// ctx.globalAlpha = 0.5;
if(renderOptions['showNextLayer'] && layerNum < model.length - 1) {
drawLayer(layerNum+1, 0, this.getLayerNumSegments(layerNum+1), true);
}
drawLayer(layerNum, fromProgress, toProgress);
}else{
console.log("Got request to render non-existent layer!!");
}
}
},
getModelNumLayers: function(){
return model?model.length:1;
},
getLayerNumSegments: function(layer){
if(model){
return model[layer]?model[layer].length:1;
}else{
return 1;
}
},
doRender: function(mdl, layerNum){
var mdlInfo;
model = mdl;
prevX=0;
prevY=0;
if(!initialized)this.init();
mdlInfo = GCODE.gCodeReader.getModelInfo();
speeds = mdlInfo.speeds;
speedsByLayer = mdlInfo.speedsByLayer;
// console.log(speeds);
// console.log(mdlInfo.min.x + ' ' + mdlInfo.modelSize.x);
offsetModelX = (gridSizeX/2-(mdlInfo.min.x+mdlInfo.modelSize.x/2))*zoomFactor;
offsetModelY = (mdlInfo.min.y+mdlInfo.modelSize.y/2)*zoomFactor-gridSizeY/2*zoomFactor;
if(ctx)ctx.translate(offsetModelX, offsetModelY);
this.render(layerNum, 0, model[layerNum].length);
},
getZ: function(layerNum){
if(!model&&!model[layerNum]){
return '-1';
}
var cmds = model[layerNum];
for(var i=0;i<cmds.length;i++){
if(cmds[i].prevZ!==undefined)return cmds[i].prevZ;
}
return '-1';
}
}
}());
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/20/12
* Time: 1:36 PM
* To change this template use File | Settings | File Templates.
*/
GCODE.renderer = (function(){
// ***** PRIVATE ******
var canvas;
var ctx;
var zoomFactor= 2.8, zoomFactorDelta = 0.4;
var gridSizeX=200,gridSizeY=200,gridStep=10;
var ctxHeight, ctxWidth;
var prevX=0, prevY=0;
// var colorGrid="#bbbbbb", colorLine="#000000";
var sliderHor, sliderVer;
var layerNumStore, progressStore={from: 0, to: -1};
var lastX, lastY;
var dragStart,dragged;
var scaleFactor = 1.1;
var model;
var initialized=false;
var renderOptions = {
showMoves: true,
showRetracts: true,
colorGrid: "#bbbbbb",
extrusionWidth: 1,
// colorLine: ["#000000", "#aabb88", "#ffe7a0", "#6e7700", "#331a00", "#44ba97", "#08262f", "#db0e00", "#ff9977"],
colorLine: ["#000000", "#45c7ba", "#a9533a", "#ff44cc", "#dd1177", "#eeee22", "#ffbb55", "#ff5511", "#777788"],
colorMove: "#00ff00",
colorRetract: "#ff0000",
colorRestart: "#0000ff",
sizeRetractSpot: 2,
modelCenter: {x: 0, y: 0},
moveModel: true,
differentiateColors: true,
showNextLayer: false
};
var offsetModelX=0, offsetModelY=0;
var speeds = [];
var speedsByLayer = {};
var reRender = function(){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
drawGrid();
if(renderOptions['showNextLayer'] && layerNumStore < model.length - 1) {
drawLayer(layerNumStore+1, 0, GCODE.renderer.getLayerNumSegments(layerNumStore+1), true);
}
drawLayer(layerNumStore, progressStore.from, progressStore.to);
};
function trackTransforms(ctx){
var svg = document.createElementNS("http://www.w3.org/2000/svg",'svg');
var xform = svg.createSVGMatrix();
ctx.getTransform = function(){ return xform; };
var savedTransforms = [];
var save = ctx.save;
ctx.save = function(){
savedTransforms.push(xform.translate(0,0));
return save.call(ctx);
};
var restore = ctx.restore;
ctx.restore = function(){
xform = savedTransforms.pop();
return restore.call(ctx);
};
var scale = ctx.scale;
ctx.scale = function(sx,sy){
xform = xform.scaleNonUniform(sx,sy);
return scale.call(ctx,sx,sy);
};
var rotate = ctx.rotate;
ctx.rotate = function(radians){
xform = xform.rotate(radians*180/Math.PI);
return rotate.call(ctx,radians);
};
var translate = ctx.translate;
ctx.translate = function(dx,dy){
xform = xform.translate(dx,dy);
return translate.call(ctx,dx,dy);
};
var transform = ctx.transform;
ctx.transform = function(a,b,c,d,e,f){
var m2 = svg.createSVGMatrix();
m2.a=a; m2.b=b; m2.c=c; m2.d=d; m2.e=e; m2.f=f;
xform = xform.multiply(m2);
return transform.call(ctx,a,b,c,d,e,f);
};
var setTransform = ctx.setTransform;
ctx.setTransform = function(a,b,c,d,e,f){
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx,a,b,c,d,e,f);
};
var pt = svg.createSVGPoint();
ctx.transformedPoint = function(x,y){
pt.x=x; pt.y=y;
return pt.matrixTransform(xform.inverse());
}
}
var startCanvas = function() {
canvas = document.getElementById('canvas');
// Проверяем понимает ли браузер canvas
if (!canvas.getContext) {
throw "exception";
}
ctx = canvas.getContext('2d'); // Получаем 2D контекст
ctxHeight = canvas.height;
ctxWidth = canvas.width;
lastX = ctxWidth/2;
lastY = ctxHeight/2;
ctx.lineWidth = 2;
ctx.lineCap = 'round';
trackTransforms(ctx);
canvas.addEventListener('mousedown',function(evt){
document.body.style.mozUserSelect = document.body.style.webkitUserSelect = document.body.style.userSelect = 'none';
lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
dragStart = ctx.transformedPoint(lastX,lastY);
dragged = false;
},false);
canvas.addEventListener('mousemove',function(evt){
lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
dragged = true;
if (dragStart){
var pt = ctx.transformedPoint(lastX,lastY);
ctx.translate(pt.x-dragStart.x,pt.y-dragStart.y);
reRender();
}
},false);
canvas.addEventListener('mouseup',function(evt){
dragStart = null;
if (!dragged) zoom(evt.shiftKey ? -1 : 1 );
},false);
var zoom = function(clicks){
var pt = ctx.transformedPoint(lastX,lastY);
ctx.translate(pt.x,pt.y);
var factor = Math.pow(scaleFactor,clicks);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
reRender();
};
var handleScroll = function(evt){
var delta;
if(evt.detail<0 || evt.wheelDelta>0)delta=zoomFactorDelta;
else delta=-1*zoomFactorDelta;
if (delta) zoom(delta);
return evt.preventDefault() && false;
};
canvas.addEventListener('DOMMouseScroll',handleScroll,false);
canvas.addEventListener('mousewheel',handleScroll,false);
};
var drawGrid = function() {
var i;
ctx.strokeStyle = renderOptions["colorGrid"];
ctx.lineWidth = 1;
var offsetX=0, offsetY=0;
if(renderOptions["moveModel"]){
offsetX = offsetModelX;
offsetY = offsetModelY;
}
ctx.beginPath();
for(i=0;i<=gridSizeX;i+=gridStep){
ctx.moveTo(i*zoomFactor-offsetX, 0-offsetY);
ctx.lineTo(i*zoomFactor-offsetX, -gridSizeY*zoomFactor-offsetY);
}
ctx.stroke();
ctx.beginPath();
for(i=0;i<=gridSizeY;i+=gridStep){
ctx.moveTo(0-offsetX, -i*zoomFactor-offsetY);
ctx.lineTo(gridSizeX*zoomFactor-offsetX, -i*zoomFactor-offsetY);
}
ctx.stroke();
};
var drawLayer = function(layerNum, fromProgress, toProgress, isNextLayer){
var i, speedIndex= 0, prevZ = 0;
isNextLayer = typeof isNextLayer !== 'undefined' ? isNextLayer : false;
if(!isNextLayer){
layerNumStore=layerNum;
progressStore = {from: fromProgress, to: toProgress};
}
if(!model||!model[layerNum])return;
var cmds = model[layerNum];
var x, y;
// if(toProgress === -1){
// toProgress=cmds.length;
// }
if(fromProgress>0){
prevX = cmds[fromProgress-1].x*zoomFactor;
prevY = -cmds[fromProgress-1].y*zoomFactor;
}else if(fromProgress===0 && layerNum==0){
if(model[0]&&model[0].x !== undefined &&model[0].y !== undefined){
prevX = model[0].x*zoomFactor;
prevY = -model[0].y*zoomFactor;
}else {
prevX = 0;
prevY = 0;
}
}else if(typeof(cmds[0].prevX) !== 'undefined' && typeof(cmds[0].prevY) !== 'undefined'){
prevX = cmds[0].prevX*zoomFactor;
prevY = -cmds[0].prevY*zoomFactor;
}else{
if(model[layerNum-1]){
prevX=undefined;
prevY=undefined;
for(i=model[layerNum-1].length-1;i>=0;i--){
if(prevX === undefined && model[layerNum-1][i].x!==undefined)prevX=model[layerNum-1][i].x*zoomFactor;
if(prevY === undefined && model[layerNum-1][i].y!==undefined)prevY=-model[layerNum-1][i].y*zoomFactor;
}
if(prevX === undefined)prevX=0;
if(prevY === undefined)prevY=0;
}else{
prevX=0;
prevY=0;
}
}
prevZ = GCODE.renderer.getZ(layerNum);
// ctx.strokeStyle = renderOptions["colorLine"];
for(i=fromProgress;i<=toProgress;i++){
ctx.lineWidth = 1;
if(typeof(cmds[i]) === 'undefined')continue;
if(typeof(cmds[i].prevX) !== 'undefined' && typeof(cmds[i].prevY) !== 'undefined'){
prevX = cmds[i].prevX*zoomFactor;
prevY = -cmds[i].prevY*zoomFactor;
}
// console.log(cmds[i]);
if(typeof(cmds[i].x)==='undefined'||isNaN(cmds[i].x))x=prevX/zoomFactor;
else x = cmds[i].x;
if(typeof(cmds[i].y) === 'undefined'||isNaN(cmds[i].y))y=prevY/zoomFactor;
else y = -cmds[i].y;
if(renderOptions["differentiateColors"]&&!renderOptions['showNextLayer']){
// if(speedsByLayer['extrude'][prevZ]){
speedIndex = speeds['extrude'].indexOf(cmds[i].speed);
// speedIndex = GCODE.ui.ArrayIndexOf(speedsByLayer['extrude'][prevZ], function(obj) {return obj.speed === cmds[i].speed;});
// } else {
// speedIndex = -1;
// }
if(speedIndex === -1){
speedIndex = 0;
}else if(speedIndex > renderOptions["colorLine"].length -1){
speedIndex = speedIndex % (renderOptions["colorLine"].length-1);
// console.log("Too much colors");
}
}else if(renderOptions['showNextLayer']&&isNextLayer){
speedIndex=3;
}else{
speedIndex=0;
}
if(!cmds[i].extrude&&!cmds[i].noMove){
// ctx.stroke();
if(cmds[i].retract == -1){
if(renderOptions["showRetracts"]){
ctx.strokeStyle = renderOptions["colorRetract"];
ctx.fillStyle = renderOptions["colorRetract"];
ctx.beginPath();
ctx.arc(prevX, prevY, renderOptions["sizeRetractSpot"], 0, Math.PI*2, true);
ctx.stroke();
ctx.fill();
}
}
if(renderOptions["showMoves"]){
ctx.strokeStyle = renderOptions["colorMove"];
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x*zoomFactor,y*zoomFactor);
ctx.stroke();
}
// ctx.strokeStyle = renderOptions["colorLine"][0];
// ctx.beginPath();
// console.log("moveto: "+cmds[i].x+":"+cmds[i].y)
// ctx.moveTo(cmds[i].x*zoomFactor,cmds[i].y*zoomFactor);
}
else if(cmds[i].extrude){
if(cmds[i].retract==0){
ctx.strokeStyle = renderOptions["colorLine"][speedIndex];
ctx.lineWidth = renderOptions['extrusionWidth'];
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x*zoomFactor,y*zoomFactor);
ctx.stroke();
}else {
if(renderOptions["showRetracts"]){
// ctx.stroke();
ctx.strokeStyle = renderOptions["colorRestart"];
ctx.fillStyle = renderOptions["colorRestart"];
ctx.beginPath();
ctx.arc(prevX, prevY, renderOptions["sizeRetractSpot"], 0, Math.PI*2, true);
ctx.stroke();
ctx.fill();
// ctx.strokeStyle = renderOptions["colorLine"][0];
// ctx.beginPath();
}
}
}
prevX = x*zoomFactor;
prevY = y*zoomFactor;
}
ctx.stroke();
};
// ***** PUBLIC *******
return {
init: function(){
startCanvas();
initialized = true;
ctx.translate(10,gridSizeY*zoomFactor+20);
},
setOption: function(options){
for(var opt in options){
if(options.hasOwnProperty(opt))renderOptions[opt] = options[opt];
};
if(initialized)reRender();
},
getOptions: function(){
return renderOptions;
},
debugGetModel: function(){
return model;
},
render: function(layerNum, fromProgress, toProgress){
if(!initialized)this.init();
if(!model){
drawGrid();
}else{
if(layerNum < model.length){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
drawGrid();
// ctx.globalAlpha = 0.5;
if(renderOptions['showNextLayer'] && layerNum < model.length - 1) {
drawLayer(layerNum+1, 0, this.getLayerNumSegments(layerNum+1), true);
}
drawLayer(layerNum, fromProgress, toProgress);
}else{
console.log("Got request to render non-existent layer!!");
}
}
},
getModelNumLayers: function(){
return model?model.length:1;
},
getLayerNumSegments: function(layer){
if(model){
return model[layer]?model[layer].length:1;
}else{
return 1;
}
},
doRender: function(mdl, layerNum){
var mdlInfo;
model = mdl;
prevX=0;
prevY=0;
if(!initialized)this.init();
mdlInfo = GCODE.gCodeReader.getModelInfo();
speeds = mdlInfo.speeds;
speedsByLayer = mdlInfo.speedsByLayer;
// console.log(speeds);
// console.log(mdlInfo.min.x + ' ' + mdlInfo.modelSize.x);
offsetModelX = (gridSizeX/2-(mdlInfo.min.x+mdlInfo.modelSize.x/2))*zoomFactor;
offsetModelY = (mdlInfo.min.y+mdlInfo.modelSize.y/2)*zoomFactor-gridSizeY/2*zoomFactor;
if(ctx)ctx.translate(offsetModelX, offsetModelY);
this.render(layerNum, 0, model[layerNum].length);
},
getZ: function(layerNum){
if(!model&&!model[layerNum]){
return '-1';
}
var cmds = model[layerNum];
for(var i=0;i<cmds.length;i++){
if(cmds[i].prevZ!==undefined)return cmds[i].prevZ;
}
return '-1';
}
}
}());

View file

@ -1,345 +1,345 @@
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/21/12
* Time: 7:45 AM
*/
var GCODE = {};
GCODE.ui = (function(){
var reader;
var myCodeMirror;
var sliderVer;
var sliderHor;
var gCodeLines = {first: 0, last: 0};
var showGCode = false;
var setProgress = function(id, progress){
$('#'+id).width(parseInt(progress)+'%');
$('#'+id).text(parseInt(progress)+'%');
};
var chooseAccordion = function(id){
// debugger;
$('#'+id).collapse("show");
};
var setLinesColor = function(toggle){
// var i=0;
// for(i=gCodeLines.first;i<gCodeLines.last; i++){
// if(toggle){
// myCodeMirror.setLineClass(Number(i), null, "activeline");
// }else{
// myCodeMirror.setLineClass(Number(i), null, null);
// }
// }
}
var printLayerInfo = function(layerNum){
var z = GCODE.renderer.getZ(layerNum);
var segments = GCODE.renderer.getLayerNumSegments(layerNum);
var filament = GCODE.gCodeReader.getLayerFilament(z);
var layerSpeeds = GCODE.gCodeReader.getModelInfo().speedsByLayer;
var renderOptions = GCODE.renderer.getOptions();
var colors = renderOptions["colorLine"];
var speedIndex = 0;
var keys, type;
var showMove=false;
var i = 0;
var output = [];
output.push("Layer number: " + layerNum);
output.push("Layer height (mm): " + z);
output.push("GCODE commands in layer: " + segments);
output.push("Filament used by layer (mm): " + filament.toFixed(2));
output.push("Print time for layer: " + parseFloat(GCODE.gCodeReader.getModelInfo().printTimeByLayer[z]).toFixed(1) + "sec");
output.push("Extrude speeds:");
for(i=0;i<layerSpeeds['extrude'][z].length;i++){
if(typeof(layerSpeeds['extrude'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<div id='colorBox"+i+"' class='colorBox' style='background-color: "+colors[speedIndex] + "'></div> = " + (parseFloat(layerSpeeds['extrude'][z][i])/60).toFixed(2)+"mm/s");
}
if(typeof(layerSpeeds['move'][z]) !== 'undefined'){
output.push("Move speeds:");
for(i=0;i<layerSpeeds['move'][z].length;i++){
if(typeof(layerSpeeds['move'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<div id='colorBox"+i+"' class='colorBox' style='background-color: "+renderOptions['colorMove'] + "'></div> = " + (parseFloat(layerSpeeds['move'][z][i])/60).toFixed(2)+"mm/s");
}
}
if(typeof(layerSpeeds['retract'][z]) !== 'undefined'){
output.push("Retract speeds:");
for(i=0;i<layerSpeeds['retract'][z].length;i++){
if(typeof(layerSpeeds['retract'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<span style='color: " + renderOptions['colorRetract'] +"'>&#9679;</span> <span style='color: " + renderOptions['colorRestart'] +"'>&#9679;</span> = " +(parseFloat(layerSpeeds['retract'][z][i])/60).toFixed(2)+"mm/s");
}
}
$('#layerInfo').html(output.join('<br>'));
// chooseAccordion('layerAccordionTab');
};
var handleFileSelect = function(evt) {
// console.log("handleFileSelect");
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer?evt.dataTransfer.files:evt.target.files; // FileList object.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
if(f.name.toLowerCase().match(/^.*\.(?:gcode|g|txt)$/)){
output.push('<li>File extensions suggests GCODE</li>');
}else{
output.push('<li><strong>You should only upload *.gcode files! I will not work with this one!</strong></li>');
document.getElementById('errorList').innerHTML = '<ul>' + output.join('') + '</ul>';
return;
}
reader = new FileReader();
reader.onload = function(theFile){
chooseAccordion('progressAccordionTab');
setProgress('loadProgress', 0);
setProgress('analyzeProgress', 0);
// myCodeMirror.setValue(theFile.target.result);
GCODE.gCodeReader.loadFile(theFile);
if(showGCode){
myCodeMirror.setValue(theFile.target.result);
}else{
myCodeMirror.setValue("GCode view is disabled. You can enable it in 'GCode analyzer options' section.")
}
};
reader.readAsText(f);
}
};
var handleDragOver = function(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.target.dropEffect = 'copy'; // Explicitly show this is a copy.
};
var initSliders = function(){
var prevX=0;
var prevY=0;
var handle;
sliderVer = $( "#slider-vertical" );
sliderHor = $( "#slider-horizontal" );
var onLayerChange = function(val){
var progress = GCODE.renderer.getLayerNumSegments(val)-1;
GCODE.renderer.render(val,0, progress);
sliderHor.slider({max: progress, values: [0,progress]});
setLinesColor(false); //clear current selection
gCodeLines = GCODE.gCodeReader.getGCodeLines(val, sliderHor.slider("values",0), sliderHor.slider("values",1));
setLinesColor(true); // highlight lines
printLayerInfo(val);
};
sliderVer.slider({
orientation: "vertical",
range: "min",
min: 0,
max: GCODE.renderer.getModelNumLayers()-1,
value: 0,
slide: function( event, ui ) {
onLayerChange(ui.value);
}
});
//this stops slider reacting to arrow keys, since we do it below manually
$( "#slider-vertical .ui-slider-handle" ).unbind('keydown');
sliderHor.slider({
orientation: "horizontal",
range: "min",
min: 0,
max: GCODE.renderer.getLayerNumSegments(0)-1,
values: [0,GCODE.renderer.getLayerNumSegments(0)-1],
slide: function( event, ui ) {
setLinesColor(false); //clear current selection
gCodeLines = GCODE.gCodeReader.getGCodeLines(sliderVer.slider("value"),ui.values[0], ui.values[1]);
setLinesColor(true); // highlight lines
GCODE.renderer.render(sliderVer.slider("value"), ui.values[0], ui.values[1]);
}
});
window.onkeydown = function (event){
if(event.keyCode === 38 || event.keyCode === 33){
if(sliderVer.slider('value') < sliderVer.slider('option', 'max')){
sliderVer.slider('value', sliderVer.slider('value')+1);
onLayerChange(sliderVer.slider('value'));
}
}else if(event.keyCode === 40 || event.keyCode === 34){
if(sliderVer.slider('value') > 0){
sliderVer.slider('value', sliderVer.slider('value')-1);
onLayerChange(sliderVer.slider('value'));
}
}
event.stopPropagation()
}
};
var processMessage = function(e){
var data = e.data;
switch (data.cmd) {
case 'returnModel':
setProgress('loadProgress', 100);
worker.postMessage({
"cmd":"analyzeModel",
"msg":{
}
}
);
break;
case 'analyzeDone':
var resultSet = [];
setProgress('analyzeProgress',100);
GCODE.gCodeReader.processAnalyzeModelDone(data.msg);
GCODE.gCodeReader.passDataToRenderer();
initSliders();
resultSet.push("Model size is: " + data.msg.modelSize.x.toFixed(2) + 'x' + data.msg.modelSize.y.toFixed(2) + 'x' + data.msg.modelSize.z.toFixed(2)+'mm<br>');
resultSet.push("Total filament used: " + data.msg.totalFilament.toFixed(2) + "mm<br>");
resultSet.push("Estimated print time: " + parseInt(parseFloat(data.msg.printTime)/60/60) + ":" + parseInt((parseFloat(data.msg.printTime)/60)%60) + ":" + parseInt(parseFloat(data.msg.printTime)%60) + "<br>");
resultSet.push("Estimated layer height: " + data.msg.layerHeight.toFixed(2) + "mm<br>");
resultSet.push("Layer count: " + data.msg.layerCnt.toFixed(0) + "printed, " + data.msg.layerTotal.toFixed(0) + 'visited<br>');
document.getElementById('list').innerHTML = resultSet.join('');
chooseAccordion('infoAccordionTab');
$('#myTab a[href="#tab2d"]').tab('show');
break;
case 'returnLayer':
GCODE.gCodeReader.processLayerFromWorker(data.msg);
setProgress('loadProgress',data.msg.progress);
break;
case 'returnMultiLayer':
GCODE.gCodeReader.processMultiLayerFromWorker(data.msg);
setProgress('loadProgress',data.msg.progress);
break;
case "analyzeProgress":
setProgress('analyzeProgress',data.msg.progress);
break;
default:
console.log("default msg received" + data.cmd);
}
};
var checkCapabilities = function(){
var warnings = [];
var fatal = [];
Modernizr.addTest('filereader', function () {
return !!(window.File && window.FileList && window.FileReader);
});
if(!Modernizr.canvas)fatal.push("<li>Your browser doesn't seem to support HTML5 Canvas, this application won't work without it.</li>");
//if(!Modernizr.filereader)fatal.push("<li>Your browser doesn't seem to support HTML5 File API, this application won't work without it.</li>");
if(!Modernizr.webworkers)fatal.push("<li>Your browser doesn't seem to support HTML5 Web Workers, this application won't work without it.</li>");
if(!Modernizr.svg)fatal.push("<li>Your browser doesn't seem to support HTML5 SVG, this application won't work without it.</li>");
if(fatal.length>0){
document.getElementById('errorList').innerHTML = '<ul>' + fatal.join('') + '</ul>';
console.log("Initialization failed: unsupported browser.")
return false;
}
if(!Modernizr.webgl && GCODE.renderer3d){
warnings.push("<li>Your browser doesn't seem to support HTML5 Web GL, 3d mode is not recommended, going to be SLOW!</li>");
GCODE.renderer3d.setOption({rendererType: "canvas"});
}
if(!Modernizr.draganddrop)warnings.push("<li>Your browser doesn't seem to support HTML5 Drag'n'Drop, Drop area will not work.</li>");
if(warnings.length>0){
document.getElementById('errorList').innerHTML = '<ul>' + wanings.join('') + '</ul>';
console.log("Initialization succeeded with warnings.")
}
return true;
};
return {
worker: undefined,
initHandlers: function(){
var capabilitiesResult = checkCapabilities();
if(!capabilitiesResult){
return;
}
setProgress('loadProgress', 0);
setProgress('analyzeProgress', 0);
worker = new Worker('static/gcodeviewer/js/Worker.js');
worker.addEventListener('message', processMessage, false);
GCODE.ui.processOptions();
GCODE.renderer.render(0,0);
console.log("Application initialized");
},
ArrayIndexOf: function(a, fnc) {
if (!fnc || typeof (fnc) != 'function') {
return -1;
}
if (!a || !a.length || a.length < 1) return -1;
for (var i = 0; i < a.length; i++) {
if(!a[i]) continue;
if (fnc(a[i])) return i;
}
return -1;
},
updateLayerInfo: function(layerNum){
printLayerInfo(layerNum);
},
processOptions: function(){
if(document.getElementById('sortLayersCheckbox').checked)GCODE.gCodeReader.setOption({sortLayers: true});
else GCODE.gCodeReader.setOption({sortLayers: false});
if(document.getElementById('purgeEmptyLayersCheckbox').checked)GCODE.gCodeReader.setOption({purgeEmptyLayers: true});
else GCODE.gCodeReader.setOption({purgeEmptyLayers: false});
if(document.getElementById('showGCodeCheckbox').checked)showGCode = true;
else showGCode = false;
// if(document.getElementById('sortLayersCheckbox').checked) worker.postMessage({"cmd":"setOption", "msg":{sortLayers: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{sortLayers: false}});
//
// if(document.getElementById('purgeEmptyLayersCheckbox').checked)worker.postMessage({"cmd":"setOption", "msg":{purgeEmptyLayers: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{purgeEmptyLayers: false}});
// if(document.getElementById('analyzeModelCheckbox').checked)worker.postMessage({"cmd":"setOption", "msg":{analyzeModel: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{analyzeModel: false}});
if(document.getElementById('moveModelCheckbox').checked)GCODE.renderer.setOption({moveModel: true});
else GCODE.renderer.setOption({moveModel: false});
if(document.getElementById('showMovesCheckbox').checked)GCODE.renderer.setOption({showMoves: true});
else GCODE.renderer.setOption({showMoves: false});
if(document.getElementById('showRetractsCheckbox').checked)GCODE.renderer.setOption({showRetracts: true});
else GCODE.renderer.setOption({showRetracts: false});
if(document.getElementById('differentiateColorsCheckbox').checked)GCODE.renderer.setOption({differentiateColors: true});
else GCODE.renderer.setOption({differentiateColors: false});
var widthMod = 2;
if(Number($('#widthModifier').attr('value'))) {widthMod = Number($('#widthModifier').attr('value'));}
if(document.getElementById('thickExtrusionCheckbox').checked)GCODE.renderer.setOption({extrusionWidth: widthMod});
else GCODE.renderer.setOption({extrusionWidth: 1});
if(document.getElementById('showNextLayer').checked)GCODE.renderer.setOption({showNextLayer: true});
else GCODE.renderer.setOption({showNextLayer: false});
}
}
/**
* User: hudbrog (hudbrog@gmail.com)
* Date: 10/21/12
* Time: 7:45 AM
*/
var GCODE = {};
GCODE.ui = (function(){
var reader;
var myCodeMirror;
var sliderVer;
var sliderHor;
var gCodeLines = {first: 0, last: 0};
var showGCode = false;
var setProgress = function(id, progress){
$('#'+id).width(parseInt(progress)+'%');
$('#'+id).text(parseInt(progress)+'%');
};
var chooseAccordion = function(id){
// debugger;
$('#'+id).collapse("show");
};
var setLinesColor = function(toggle){
// var i=0;
// for(i=gCodeLines.first;i<gCodeLines.last; i++){
// if(toggle){
// myCodeMirror.setLineClass(Number(i), null, "activeline");
// }else{
// myCodeMirror.setLineClass(Number(i), null, null);
// }
// }
}
var printLayerInfo = function(layerNum){
var z = GCODE.renderer.getZ(layerNum);
var segments = GCODE.renderer.getLayerNumSegments(layerNum);
var filament = GCODE.gCodeReader.getLayerFilament(z);
var layerSpeeds = GCODE.gCodeReader.getModelInfo().speedsByLayer;
var renderOptions = GCODE.renderer.getOptions();
var colors = renderOptions["colorLine"];
var speedIndex = 0;
var keys, type;
var showMove=false;
var i = 0;
var output = [];
output.push("Layer number: " + layerNum);
output.push("Layer height (mm): " + z);
output.push("GCODE commands in layer: " + segments);
output.push("Filament used by layer (mm): " + filament.toFixed(2));
output.push("Print time for layer: " + parseFloat(GCODE.gCodeReader.getModelInfo().printTimeByLayer[z]).toFixed(1) + "sec");
output.push("Extrude speeds:");
for(i=0;i<layerSpeeds['extrude'][z].length;i++){
if(typeof(layerSpeeds['extrude'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<div id='colorBox"+i+"' class='colorBox' style='background-color: "+colors[speedIndex] + "'></div> = " + (parseFloat(layerSpeeds['extrude'][z][i])/60).toFixed(2)+"mm/s");
}
if(typeof(layerSpeeds['move'][z]) !== 'undefined'){
output.push("Move speeds:");
for(i=0;i<layerSpeeds['move'][z].length;i++){
if(typeof(layerSpeeds['move'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<div id='colorBox"+i+"' class='colorBox' style='background-color: "+renderOptions['colorMove'] + "'></div> = " + (parseFloat(layerSpeeds['move'][z][i])/60).toFixed(2)+"mm/s");
}
}
if(typeof(layerSpeeds['retract'][z]) !== 'undefined'){
output.push("Retract speeds:");
for(i=0;i<layerSpeeds['retract'][z].length;i++){
if(typeof(layerSpeeds['retract'][z][i])==='undefined'){continue;}
speedIndex = i;
if(speedIndex > colors.length -1){speedIndex = speedIndex % (colors.length-1);}
output.push("<span style='color: " + renderOptions['colorRetract'] +"'>&#9679;</span> <span style='color: " + renderOptions['colorRestart'] +"'>&#9679;</span> = " +(parseFloat(layerSpeeds['retract'][z][i])/60).toFixed(2)+"mm/s");
}
}
$('#layerInfo').html(output.join('<br>'));
// chooseAccordion('layerAccordionTab');
};
var handleFileSelect = function(evt) {
// console.log("handleFileSelect");
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer?evt.dataTransfer.files:evt.target.files; // FileList object.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
if(f.name.toLowerCase().match(/^.*\.(?:gcode|g|txt)$/)){
output.push('<li>File extensions suggests GCODE</li>');
}else{
output.push('<li><strong>You should only upload *.gcode files! I will not work with this one!</strong></li>');
document.getElementById('errorList').innerHTML = '<ul>' + output.join('') + '</ul>';
return;
}
reader = new FileReader();
reader.onload = function(theFile){
chooseAccordion('progressAccordionTab');
setProgress('loadProgress', 0);
setProgress('analyzeProgress', 0);
// myCodeMirror.setValue(theFile.target.result);
GCODE.gCodeReader.loadFile(theFile);
if(showGCode){
myCodeMirror.setValue(theFile.target.result);
}else{
myCodeMirror.setValue("GCode view is disabled. You can enable it in 'GCode analyzer options' section.")
}
};
reader.readAsText(f);
}
};
var handleDragOver = function(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.target.dropEffect = 'copy'; // Explicitly show this is a copy.
};
var initSliders = function(){
var prevX=0;
var prevY=0;
var handle;
sliderVer = $( "#slider-vertical" );
sliderHor = $( "#slider-horizontal" );
var onLayerChange = function(val){
var progress = GCODE.renderer.getLayerNumSegments(val)-1;
GCODE.renderer.render(val,0, progress);
sliderHor.slider({max: progress, values: [0,progress]});
setLinesColor(false); //clear current selection
gCodeLines = GCODE.gCodeReader.getGCodeLines(val, sliderHor.slider("values",0), sliderHor.slider("values",1));
setLinesColor(true); // highlight lines
printLayerInfo(val);
};
sliderVer.slider({
orientation: "vertical",
range: "min",
min: 0,
max: GCODE.renderer.getModelNumLayers()-1,
value: 0,
slide: function( event, ui ) {
onLayerChange(ui.value);
}
});
//this stops slider reacting to arrow keys, since we do it below manually
$( "#slider-vertical .ui-slider-handle" ).unbind('keydown');
sliderHor.slider({
orientation: "horizontal",
range: "min",
min: 0,
max: GCODE.renderer.getLayerNumSegments(0)-1,
values: [0,GCODE.renderer.getLayerNumSegments(0)-1],
slide: function( event, ui ) {
setLinesColor(false); //clear current selection
gCodeLines = GCODE.gCodeReader.getGCodeLines(sliderVer.slider("value"),ui.values[0], ui.values[1]);
setLinesColor(true); // highlight lines
GCODE.renderer.render(sliderVer.slider("value"), ui.values[0], ui.values[1]);
}
});
window.onkeydown = function (event){
if(event.keyCode === 38 || event.keyCode === 33){
if(sliderVer.slider('value') < sliderVer.slider('option', 'max')){
sliderVer.slider('value', sliderVer.slider('value')+1);
onLayerChange(sliderVer.slider('value'));
}
}else if(event.keyCode === 40 || event.keyCode === 34){
if(sliderVer.slider('value') > 0){
sliderVer.slider('value', sliderVer.slider('value')-1);
onLayerChange(sliderVer.slider('value'));
}
}
event.stopPropagation()
}
};
var processMessage = function(e){
var data = e.data;
switch (data.cmd) {
case 'returnModel':
setProgress('loadProgress', 100);
worker.postMessage({
"cmd":"analyzeModel",
"msg":{
}
}
);
break;
case 'analyzeDone':
var resultSet = [];
setProgress('analyzeProgress',100);
GCODE.gCodeReader.processAnalyzeModelDone(data.msg);
GCODE.gCodeReader.passDataToRenderer();
initSliders();
resultSet.push("Model size is: " + data.msg.modelSize.x.toFixed(2) + 'x' + data.msg.modelSize.y.toFixed(2) + 'x' + data.msg.modelSize.z.toFixed(2)+'mm<br>');
resultSet.push("Total filament used: " + data.msg.totalFilament.toFixed(2) + "mm<br>");
resultSet.push("Estimated print time: " + parseInt(parseFloat(data.msg.printTime)/60/60) + ":" + parseInt((parseFloat(data.msg.printTime)/60)%60) + ":" + parseInt(parseFloat(data.msg.printTime)%60) + "<br>");
resultSet.push("Estimated layer height: " + data.msg.layerHeight.toFixed(2) + "mm<br>");
resultSet.push("Layer count: " + data.msg.layerCnt.toFixed(0) + "printed, " + data.msg.layerTotal.toFixed(0) + 'visited<br>');
document.getElementById('list').innerHTML = resultSet.join('');
chooseAccordion('infoAccordionTab');
$('#myTab a[href="#tab2d"]').tab('show');
break;
case 'returnLayer':
GCODE.gCodeReader.processLayerFromWorker(data.msg);
setProgress('loadProgress',data.msg.progress);
break;
case 'returnMultiLayer':
GCODE.gCodeReader.processMultiLayerFromWorker(data.msg);
setProgress('loadProgress',data.msg.progress);
break;
case "analyzeProgress":
setProgress('analyzeProgress',data.msg.progress);
break;
default:
console.log("default msg received" + data.cmd);
}
};
var checkCapabilities = function(){
var warnings = [];
var fatal = [];
Modernizr.addTest('filereader', function () {
return !!(window.File && window.FileList && window.FileReader);
});
if(!Modernizr.canvas)fatal.push("<li>Your browser doesn't seem to support HTML5 Canvas, this application won't work without it.</li>");
//if(!Modernizr.filereader)fatal.push("<li>Your browser doesn't seem to support HTML5 File API, this application won't work without it.</li>");
if(!Modernizr.webworkers)fatal.push("<li>Your browser doesn't seem to support HTML5 Web Workers, this application won't work without it.</li>");
if(!Modernizr.svg)fatal.push("<li>Your browser doesn't seem to support HTML5 SVG, this application won't work without it.</li>");
if(fatal.length>0){
document.getElementById('errorList').innerHTML = '<ul>' + fatal.join('') + '</ul>';
console.log("Initialization failed: unsupported browser.")
return false;
}
if(!Modernizr.webgl && GCODE.renderer3d){
warnings.push("<li>Your browser doesn't seem to support HTML5 Web GL, 3d mode is not recommended, going to be SLOW!</li>");
GCODE.renderer3d.setOption({rendererType: "canvas"});
}
if(!Modernizr.draganddrop)warnings.push("<li>Your browser doesn't seem to support HTML5 Drag'n'Drop, Drop area will not work.</li>");
if(warnings.length>0){
document.getElementById('errorList').innerHTML = '<ul>' + wanings.join('') + '</ul>';
console.log("Initialization succeeded with warnings.")
}
return true;
};
return {
worker: undefined,
initHandlers: function(){
var capabilitiesResult = checkCapabilities();
if(!capabilitiesResult){
return;
}
setProgress('loadProgress', 0);
setProgress('analyzeProgress', 0);
worker = new Worker('static/gcodeviewer/js/Worker.js');
worker.addEventListener('message', processMessage, false);
GCODE.ui.processOptions();
GCODE.renderer.render(0,0);
console.log("Application initialized");
},
ArrayIndexOf: function(a, fnc) {
if (!fnc || typeof (fnc) != 'function') {
return -1;
}
if (!a || !a.length || a.length < 1) return -1;
for (var i = 0; i < a.length; i++) {
if(!a[i]) continue;
if (fnc(a[i])) return i;
}
return -1;
},
updateLayerInfo: function(layerNum){
printLayerInfo(layerNum);
},
processOptions: function(){
if(document.getElementById('sortLayersCheckbox').checked)GCODE.gCodeReader.setOption({sortLayers: true});
else GCODE.gCodeReader.setOption({sortLayers: false});
if(document.getElementById('purgeEmptyLayersCheckbox').checked)GCODE.gCodeReader.setOption({purgeEmptyLayers: true});
else GCODE.gCodeReader.setOption({purgeEmptyLayers: false});
if(document.getElementById('showGCodeCheckbox').checked)showGCode = true;
else showGCode = false;
// if(document.getElementById('sortLayersCheckbox').checked) worker.postMessage({"cmd":"setOption", "msg":{sortLayers: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{sortLayers: false}});
//
// if(document.getElementById('purgeEmptyLayersCheckbox').checked)worker.postMessage({"cmd":"setOption", "msg":{purgeEmptyLayers: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{purgeEmptyLayers: false}});
// if(document.getElementById('analyzeModelCheckbox').checked)worker.postMessage({"cmd":"setOption", "msg":{analyzeModel: true}});
// else worker.postMessage({"cmd":"setOption", "msg":{analyzeModel: false}});
if(document.getElementById('moveModelCheckbox').checked)GCODE.renderer.setOption({moveModel: true});
else GCODE.renderer.setOption({moveModel: false});
if(document.getElementById('showMovesCheckbox').checked)GCODE.renderer.setOption({showMoves: true});
else GCODE.renderer.setOption({showMoves: false});
if(document.getElementById('showRetractsCheckbox').checked)GCODE.renderer.setOption({showRetracts: true});
else GCODE.renderer.setOption({showRetracts: false});
if(document.getElementById('differentiateColorsCheckbox').checked)GCODE.renderer.setOption({differentiateColors: true});
else GCODE.renderer.setOption({differentiateColors: false});
var widthMod = 2;
if(Number($('#widthModifier').attr('value'))) {widthMod = Number($('#widthModifier').attr('value'));}
if(document.getElementById('thickExtrusionCheckbox').checked)GCODE.renderer.setOption({extrusionWidth: widthMod});
else GCODE.renderer.setOption({extrusionWidth: 1});
if(document.getElementById('showNextLayer').checked)GCODE.renderer.setOption({showNextLayer: true});
else GCODE.renderer.setOption({showNextLayer: false});
}
}
}());

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 197 B

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View file

Before

Width:  |  Height:  |  Size: 780 B

After

Width:  |  Height:  |  Size: 780 B

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 721 B

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 815 B

After

Width:  |  Height:  |  Size: 815 B

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Some files were not shown because too many files have changed in this diff Show more