Commit 834fa326 authored by gijs's avatar gijs
Browse files

Initial commit

parents
* Requirements
Python 2.5+ (a bit obvious)
Sqlite3
Bottle (http://bottlepy.org/docs/dev/tutorial.html#installation)
CherryPy - optional, only as a different (faster) server - (http://download.cherrypy.org/cherrypy/3.2.2/)
* Installation
Simply copy the folder or it's contents to a nice location on the harddrive
* Usage
The application is split into two parts: app.py (the server) and listener.py (the script
that sends the commands to the plotter).
The application can be run in to modes, with a virtual or a hardware plotter. The virtual plotter
mode is mainly used to test the application - while running in virtual mode listener.py doesn't have
to be started.
The server is started, if you are in the same directory as app.py with the following command:
python app.py [mode] [host] [port] [server]
python app.py [virtual/hardware] localhost 8080 [bottle/cherrypy]
The listener is simply started by typing:
python listener.py
At first we need to start a drawing session by accessing - every time you load a new sheet in the
plotter you could start a new session to have a blank canvas:
host:port/new_session
localhost:8080/new_session
Now the application is accesible through
host:port
localhost:8080
On the left is the drawingcanvas. On the right the controls. The dropdown menu sets the pen thats
used to draw. The other controls are pretty straightforward:
- line - simply follows the mouse, and draws a line
- polyline - mouse-click adds a point to the line. The line is finished by pressing the enter key
- circle - draws a circle, holding the ctrl key makes the onmousedown point to be it's center
- rectangle - draws rectangular shapes, holding shift makes it draw squares, holding ctrl makes
the onmousedown point to be it's center
from bottle import view, route, run, route, request, install, template, response, static_file
from sqlite3 import IntegrityError, Error
from bottle_sqlite import SQLitePlugin
from json import dumps
from chiplotle import *
from chiplotle.tools.plottertools import instantiate_virtual_plotter
from sys import argv
install (SQLitePlugin(dbfile='plotter.db'))
VIRTUAL_PLOTTER = 0
HARDWARE_PLOTTER = 1
BOTTLE_SERVER = 0
CHERRYPY_SERVER = 1
# Defines whether we use Chiplotle's virtual plotter - useful for testing -
# or the hardware plotter. It needs to be connected to instantiate a session!
PLOTTER_TYPE = HARDWARE_PLOTTER if argv[1].lower() == 'hardware' else VIRTUAL_PLOTTER
# The host for the server
HOST = argv[2]
# Used port
PORT = int (argv[3])
# Used server. Cherrpy is advised in production, but needs to be installed
# Otherwise user bottle's build-in server, but it might get slow.
SERVER = CHERRYPY_SERVER if argv[4].lower() == 'cherrypy' else BOTTLE_SERVER
@route('/')
@route('/index')
def index (db):
return template('canvas')
@route('/command', method='POST')
def command(db):
command = request.forms.command
c = db.cursor();
try:
c.execute("INSERT INTO commands (command,session) VALUES(:command, (SELECT id FROM sessions WHERE active = 1))", {'command': command})
db.commit ()
except:
return dumps ({'command': command, 'code': 200})
return dumps ({'command': command, 'code': 100, 'id': c.lastrowid})
@route('/instantiate')
def instantiate (db):
try:
session = db.execute("SELECT * FROM sessions WHERE active = 1").fetchone()
except:
return dumps ({'code': 200})
return dumps ({'top': session['top'], 'bottom': session['bottom'], 'left': session ['left'], 'right': session['right'], 'session': session['id']})
@route('/active_session')
def active_session(db):
session = db.execute("SELECT * FROM sessions WHERE active = 1").fetchone()
return dumps ({'session': session['id']})
@route('/new_session')
def new_session(db):
if PLOTTER_TYPE == HARDWARE_PLOTTER:
plotter = instantiate_plotters()[0]
else:
plotter = instantiate_virtual_plotter (type='HP7576A')
margins = plotter.margins.soft
left = margins.left
right = margins.right
top = margins.top
bottom = margins.bottom
try:
db.execute("UPDATE sessions SET active = 0 WHERE active = 1")
db.execute("INSERT INTO sessions (active, top, right, bottom, left) VALUES(1, :top, :right, :bottom, :left)", {'top': top, 'right': right, 'bottom': bottom, 'left': left})
db.commit ()
except:
return dumps ({'code': 200})
return dumps ({'code': 100})
@route('/get_commands')
@route('/get_commands/<session:int>')
def get_commands(db, session=False):
commands = []
if session == False:
session = db.execute("SELECT id FROM sessions WHERE active = 1").fetchone()['id']
for row in db.execute ('SELECT c.command, c.id FROM commands c JOIN sessions s ON s.id = c.session WHERE s.active = 1 ORDER BY c.timestamp ASC').fetchall():
commands.append ({'command': row['command'], 'id': row['id']})
else:
for row in db.execute ('SELECT c.command, c.id FROM commands c WHERE c.session = :session ORDER BY c.timestamp ASC', {'session': session}).fetchall():
commands.append ({'command': row['command'], 'id': row['id']})
return dumps ({'code': 100, 'commands': commands, 'session': session})
@route('/js/<filename>')
def js (filename):
return static_file (filename, root='js')
#run (host="192.168.1.39", port=8080)
if SERVER == BOTTLE_SERVER:
run (host=HOST, port=PORT)
if SERVER == CHERRYPY_SERVER:
run (server='cherrypy', host=HOST, port=PORT)
\ No newline at end of file
SELECT c.command FROM commands c JOIN sessions s ON s.id = c.session WHERE s.active = 1 AND c.done = 0 ORDER BY timestamp ASC
UPDATE commands SET done = 1 WHERE id = ?
INSERT INTO sessions (active) VALUES(1)
INSERT INTO commands (command,session) VALUES('PD1000,2000,2000,2000;PU',1)
CREATE TABLE commands (
id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
command TEXT,
session INTEGER,
top INTEGER,
right INTEGER,
bottom INTEGER,
left INTEGER,
done INTEGER DEFAULT 0,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE sessions (
id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
active INTEGER DEFAULT 0
);
var activePath;
var plotBounds = null;
var line = new Line ();
var circle = new Circle ();
var polyline = new Polyline ();
var rectangle = new Rectangle ();
var device = null;
var pen = 0;
var commandBuffer = new Array;
var canvasCommands = new Array;
var canvasBounds = null;
var activeSession = null;
var penColors = ['#000000', '#09bee5', '#ff0064', '#fcff00', '#000000']
var activeColor = penColors[0]
function Line () {
this.activePath = new Path ()
this.onMouseDown=function (event) {
this.activePath = new Path();
this.activePath.strokeColor = activeColor;
}
this.onMouseDrag=function (event) {
this.activePath.add(event.point);
}
this.onMouseUp=function (event) {
this.activePath.simplify ()
this.activePath.flatten (4)
var points = new Array;
for (i=0;i<this.activePath.segments.length;i++) {
point = transformPoint (this.activePath.segments[i].point)
points.push (point.x + ',' + point.y)
}
command = 'PA' + points.shift() + ';PD' + points.join (',') + ';'
sendCommand (command)
}
this.onMouseMove=function (event) {
}
this.onKeyDown=function (event) {
}
this.onKeyUp=function (event) {
}
}
function Polyline () {
this.activePath = new Path ();
this.onMouseDown=function (event) {
if (this.activePath.segments.length == 0) {
this.activePath = new Path ();
this.activePath.strokeColor = activeColor;
this.activePath.add(event.point);
}
this.activePath.add(event.point);
}
this.onMouseDrag=function (event) {
this.activePath.lastSegment.point = event.point
}
this.onMouseUp=function (event) {
this.activePath.lastSegment.point = event.point
}
this.onMouseMove=function (event) {
if (this.activePath.segments.length > 0) {
this.activePath.lastSegment.point = event.point
}
}
this.onKeyDown=function (event) {
if (event.key == 'enter') {
var points = new Array;
this.activePath.removeSegment (this.activePath.segments.length-1)
for (i=0;i<this.activePath.segments.length;i++) {
var point = transformPoint (this.activePath.segments[i].point);
points.push (point.x + ',' + point.y);
}
if (points.length > 1) {
command = 'PA' + points.shift() + ';PD' + points.join (',') + ';';
} else {
command = 'PA' + points.shift() + ';PD;';
}
sendCommand (command);
this.activePath = new Path();
}
}
this.onKeyUp=function (event) {
}
}
function Circle () {
this.point = new Point(0,0)
this.lastpoint = new Point(0,0)
this.origin = new Point (0,0)
this.radius = 0
this.circle = new Path.Circle (this.origin,this.radius)
this.event = null
this.setRadius=function () {
radius = Math.sqrt ((Math.pow (this.point.x - this.lastpoint.x, 2) + Math.pow (this.point.y - this.lastpoint.y, 2)));
this.radius = (this.event.modifiers.control) ? radius : radius * 0.5
}
this.setOrigin=function (origin) {
if (this.event.modifiers.control) {
var origin = new Point (this.point.x, this.point.y);
} else {
distance = Math.sqrt (Math.pow (this.radius, 2) / 2);
var x = (this.lastpoint.x - this.point.x < 0) ? this.point.x - distance : this.point.x + distance;
var y = (this.lastpoint.y - this.point.y < 0) ? this.point.y - distance : this.point.y + distance;
var origin = new Point (x,y)
}
this.origin = origin;
}
this.draw = function () {
this.circle.remove();
this.circle = new Path.Circle (this.origin, this.radius)
this.circle.strokeColor = activeColor;
}
this.detach = function () {
this.point = new Point (0,0)
this.lastpoint = new Point (0,0)
this.origin = new Point (0,0)
this.radius = 0
this.circle = new Path.Circle (this.origin, this.radius)
this.circle.strokeColor = activeColor;
}
this.onMouseDown=function (event) {
this.event = event;
this.point = event.point;
this.lastpoint = event.point;
this.setRadius ();
this.setOrigin ();
this.draw ()
}
this.onMouseDrag=function (event) {
this.lastpoint = event.point;
this.setRadius ();
this.setOrigin ();
this.draw ()
}
this.onMouseUp=function (event) {
this.lastpoint = event.point;
this.setRadius ();
this.setOrigin ();
this.draw ()
var origin = transformPoint (this.origin)
plotradius = convertToPlotterPoints (this.radius)
command = 'PA' + origin.x + ',' + origin.y + ';CI' + plotradius + ';'
sendCommand (command)
this.detach ();
}
this.onMouseMove=function (event) {
}
this.onKeyDown=function (event) {
this.event = event;
this.setRadius ();
this.setOrigin ();
this.draw ()
}
this.onKeyUp=function (event) {
this.event = event;
this.setRadius ();
this.setOrigin ();
this.draw ()
}
}
function Rectangle () {
this.point = new Point(0,0)
this.lastpoint = new Point(0,0)
this.size = [0,0]
this.origin = [0,0]
this.rectangle = new Path.Rectangle (this.size, this.origin)
this.event = null
this.setSize=function () {
var dx = Math.abs (this.lastpoint.x - this.point.x);
var dy = Math.abs (this.lastpoint.y - this.point.y);
if (this.event.modifiers.shift) {
size = (dx > dy) ? [dx, dx] : [dy, dy];
} else {
size = [dx, dy]
}
this.size = (this.event.modifiers.control) ? [size[0] * 2, size[1] * 2] : size;
}
this.setOrigin=function () {
if (this.event.modifiers.control) {
origin = new Point (this.point.x - this.size[0] * 0.5, this.point.y - this.size[1] * 0.5);
} else {
origin = new Point (this.point.x, this.point.y);
var dx = this.lastpoint.x - this.point.x;
var dy = this.lastpoint.y - this.point.y;
if (dx < 0)
origin.x = origin.x - size[0];
if (dy < 0)
origin.y = origin.y - size[1];
}
this.origin = origin;
}
this.draw = function () {
this.rectangle.remove();
this.rectangle = new Path.Rectangle (this.origin, this.size)
this.rectangle.strokeColor = activeColor;
}
this.detach = function () {
this.point = new Point(0,0)
this.lastpoint = new Point(0,0)
this.size = [0,0]
this.origin = [0,0]
this.rectangle = new Path.Rectangle (this.size, this.origin)
this.event = null
}
this.onMouseDown=function (event) {
this.event = event;
this.point = event.point;
this.lastpoint = event.point;
this.setSize();
this.setOrigin();
this.draw();
}
this.onMouseDrag=function (event) {
this.event = event;
this.lastpoint = event.point;
this.setSize();
this.setOrigin();
this.draw();
}
this.onMouseUp=function (event) {
this.event = event;
this.lastpoint = event.point;
this.setSize();
this.setOrigin();
this.draw();
origin = transformPoint (this.origin);
width = convertToPlotterPoints (this.size[0]).toFixed(2);
height = convertToPlotterPoints (this.size[1]).toFixed(2);
command = 'PA' + origin.x + ',' + origin.y + ';PR;PD0,' + width + ',' + height + ',0,0,' + width * -1 + ',' + height * -1 + ',0;'
sendCommand (command)
this.detach();
}
this.onMouseMove=function (event) {
}
this.onKeyDown=function (event) {
this.event = event;
this.setSize();
this.setOrigin();
this.draw();
}
this.onKeyUp=function (event) {
this.event = event;
this.setSize();
this.setOrigin();
this.draw();
}
}
function drawHPGL () {
this.point = new Point (0,0);
this.penDown = 0;
this.penUp = 1;
this.penState = this.penUp;
this.noPen = 0;
this.pen = this.noPen;
this.coordAbsolute = 1;
this.coordRelative = 0;
this.coordSystem = this.coordAbsolute;
this.color = 'Black';
this.path = null;
this.knownCommands = ['PD','PU','PA','PR','CI','SP']
this.commandMatch = /[a-z]+/i
this.argumentMatch = /[0-9\.,-]+/
this.commandSplit = ';'
this.argumentSplit = ','
this.SP = function () {
if (arguments.length > 0) {
this.pen = arguments[0];
this.color = penColors[this.pen - 1]
} else {
this.pen = this.noPen;
}
}
this.CI = function (r) {
this.drawCircle (r)
}
this.PR = function () {
this.coordSystem = this.coordRelative;
}
this.PA = function () {
this.coordSystem = this.coordAbsolute;
if (arguments.length > 1) {
for (var i=0;i < arguments.length; i=i+2) {
this.moveTo (arguments[i], arguments[i+1]);
}
}
}
this.PD = function () {
this.penState = this.penDown;
this.createPath ();
for (var i=0;i < arguments.length; i=i+2) {
this.moveTo (arguments[i], arguments[i+1]);
}
}
this.PU = function () {
this.penState = this.penUp;
this.closePath ()
}
this.createPath = function () {
this.path = new Path ();
this.path.add (transformCoords (this.point))
this.path.strokeColor = this.color;
}
this.closePath = function () {
this.path = null;
}
this.moveTo = function () {
this.point = (this.coordSystem == this.coordAbsolute) ? new Point (arguments[0], arguments[1]) : this.point + new Point (arguments[0], arguments[1]);
if (this.penState == this.penDown) {
this.lineTo (this.point);
}
}
this.lineTo = function (point) {
if (this.pen != this.noPen) {
this.path.add (transformCoords (point));
}
}
this.drawCircle = function (radius) {
if (this.pen != this.noPen) {
c = new Path.Circle (transformCoords (this.point), convertToCanvasPoints (radius));
}
c.strokeColor = this.color;
}
this.parse = function () {
if (arguments != undefined) {
for (var i=0;i < arguments.length; i++) {
commands = arguments[i].split (this.commandSplit);
for (var c=0; c < commands.length; c++) {
if (commands[c].length > 0) {
command = commands[c].match (this.commandMatch)[0].toUpperCase()
args = commands[c].match (this.argumentMatch)
if (args != null) {
args = args[0].split (this.argumentSplit)
for (var a = 0; a < args.length; a++) {
args[a] = parseFloat (args[a])
}
} else {
args = []
}
if (this.knownCommands.indexOf (command) > -1) {
this[command].apply(this, args)
}
}
}
}
}
}
}
$(document).ready (function () {
$(window).resize(function() {
scaleCanvas();
});
showMessage ('Starting up')
scaleCanvas();
startPlotter ();
device = line;
pen