drawing
This commit is contained in:
parent
8a493aed30
commit
09eaa8faa3
|
@ -1,3 +1,5 @@
|
||||||
from device import Device
|
from device import Device
|
||||||
|
|
||||||
|
from drawing import Drawing
|
||||||
|
|
||||||
from planner import Planner
|
from planner import Planner
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from math import modf
|
from math import modf
|
||||||
|
from planner import Planner
|
||||||
from serial import Serial
|
from serial import Serial
|
||||||
from serial.tools.list_ports import comports
|
from serial.tools.list_ports import comports
|
||||||
import time
|
import time
|
||||||
|
@ -6,6 +7,13 @@ import time
|
||||||
STEPS_PER_INCH = 2032
|
STEPS_PER_INCH = 2032
|
||||||
STEPS_PER_MM = 80
|
STEPS_PER_MM = 80
|
||||||
|
|
||||||
|
PEN_UP_DELAY = 400
|
||||||
|
PEN_DOWN_DELAY = 400
|
||||||
|
|
||||||
|
ACCELERATION = 10
|
||||||
|
MAX_VELOCITY = 5
|
||||||
|
CORNER_FACTOR = 0.001
|
||||||
|
|
||||||
VID_PID = '04D8:FD92'
|
VID_PID = '04D8:FD92'
|
||||||
|
|
||||||
def find_port():
|
def find_port():
|
||||||
|
@ -15,12 +23,21 @@ def find_port():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class Device(object):
|
class Device(object):
|
||||||
def __init__(self, steps_per_unit=STEPS_PER_INCH):
|
def __init__(self):
|
||||||
port = find_port()
|
port = find_port()
|
||||||
if port is None:
|
if port is None:
|
||||||
raise Exception('cannot find axidraw device')
|
raise Exception('cannot find axidraw device')
|
||||||
self.serial = Serial(port, timeout=1)
|
self.serial = Serial(port, timeout=1)
|
||||||
self.steps_per_unit = steps_per_unit
|
self.steps_per_unit = STEPS_PER_INCH
|
||||||
|
self.pen_up_delay = PEN_UP_DELAY
|
||||||
|
self.pen_down_delay = PEN_DOWN_DELAY
|
||||||
|
self.acceleration = ACCELERATION
|
||||||
|
self.max_velocity = MAX_VELOCITY
|
||||||
|
self.corner_factor = CORNER_FACTOR
|
||||||
|
|
||||||
|
def make_planner(self):
|
||||||
|
return Planner(
|
||||||
|
self.acceleration, self.max_velocity, self.corner_factor)
|
||||||
|
|
||||||
def readline(self):
|
def readline(self):
|
||||||
return self.serial.readline().strip()
|
return self.serial.readline().strip()
|
||||||
|
@ -66,9 +83,25 @@ class Device(object):
|
||||||
t += step_s
|
t += step_s
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
# pen functions
|
def run_path(self, path):
|
||||||
def pen_up(self, delay=0):
|
planner = self.make_planner()
|
||||||
return self.command('SP', 1, delay)
|
plan = planner.plan(path)
|
||||||
|
self.run_plan(plan)
|
||||||
|
|
||||||
def pen_down(self, delay=0):
|
def run_drawing(self, drawing):
|
||||||
return self.command('SP', 0, delay)
|
self.pen_up()
|
||||||
|
position = (0, 0)
|
||||||
|
for path in drawing.paths:
|
||||||
|
self.run_path([position, path[0]])
|
||||||
|
self.pen_down()
|
||||||
|
self.run_path(path)
|
||||||
|
self.pen_up()
|
||||||
|
position = path[-1]
|
||||||
|
self.run_path([position, (0, 0)])
|
||||||
|
|
||||||
|
# pen functions
|
||||||
|
def pen_up(self):
|
||||||
|
return self.command('SP', 1, self.pen_up_delay)
|
||||||
|
|
||||||
|
def pen_down(self):
|
||||||
|
return self.command('SP', 0, self.pen_down_delay)
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
from math import sin, cos, radians
|
||||||
|
|
||||||
|
class Drawing(object):
|
||||||
|
def __init__(self, paths=None):
|
||||||
|
self.paths = paths or []
|
||||||
|
self._bounds = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bounds(self):
|
||||||
|
if not self._bounds:
|
||||||
|
points = [(x, y) for path in self.paths for x, y in path]
|
||||||
|
if points:
|
||||||
|
x1 = min(x for x, y in points)
|
||||||
|
x2 = max(x for x, y in points)
|
||||||
|
y1 = min(y for x, y in points)
|
||||||
|
y2 = max(y for x, y in points)
|
||||||
|
else:
|
||||||
|
x1 = x2 = y1 = y2 = 0
|
||||||
|
self._bounds = (x1, y1, x2, y2)
|
||||||
|
return self._bounds
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
x1, y1, x2, y2 = self.bounds
|
||||||
|
return x2 - x1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
x1, y1, x2, y2 = self.bounds
|
||||||
|
return y2 - y1
|
||||||
|
|
||||||
|
# def sort_paths_greedy(self, reversable=True):
|
||||||
|
# return Drawing(planner.sort_paths_greedy(self.paths, reversable))
|
||||||
|
|
||||||
|
# def join_paths(self, tolerance=0.05):
|
||||||
|
# return Drawing(util.join_paths(self.paths, tolerance))
|
||||||
|
|
||||||
|
# def remove_duplicates(self):
|
||||||
|
# return Drawing(util.remove_duplicates(self.paths))
|
||||||
|
|
||||||
|
# def simplify_paths(self, tolerance=0.05):
|
||||||
|
# return Drawing(util.simplify_paths(self.paths, tolerance))
|
||||||
|
|
||||||
|
def transform(self, func):
|
||||||
|
return Drawing([[func(x, y) for x, y in path] for path in self.paths])
|
||||||
|
|
||||||
|
def translate(self, dx, dy):
|
||||||
|
def func(x, y):
|
||||||
|
return (x + dx, y + dy)
|
||||||
|
return self.transform(func)
|
||||||
|
|
||||||
|
def scale(self, sx, sy):
|
||||||
|
def func(x, y):
|
||||||
|
return (x * sx, y * sy)
|
||||||
|
return self.transform(func)
|
||||||
|
|
||||||
|
def rotate(self, angle):
|
||||||
|
c = cos(radians(angle))
|
||||||
|
s = sin(radians(angle))
|
||||||
|
def func(x, y):
|
||||||
|
return (x * c - y * s, y * c + x * s)
|
||||||
|
return self.transform(func)
|
||||||
|
|
||||||
|
def move(self, x, y, ax, ay):
|
||||||
|
x1, y1, x2, y2 = self.bounds
|
||||||
|
dx = x1 + (x2 - x1) * ax - x
|
||||||
|
dy = y1 + (y2 - y1) * ay - y
|
||||||
|
return self.translate(-dx, -dy)
|
||||||
|
|
||||||
|
def origin(self):
|
||||||
|
return self.move(0, 0, 0, 0)
|
||||||
|
|
||||||
|
def rotate_to_fit(self, width, height, step=5):
|
||||||
|
for angle in range(0, 180, step):
|
||||||
|
drawing = self.rotate(angle)
|
||||||
|
if drawing.width <= width and drawing.height <= height:
|
||||||
|
return drawing.origin()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def scale_to_fit(self, width, height, padding=0):
|
||||||
|
width -= padding * 2
|
||||||
|
height -= padding * 2
|
||||||
|
scale = min(width / self.width, height / self.height)
|
||||||
|
return self.scale(scale, scale).origin()
|
||||||
|
|
||||||
|
def rotate_and_scale_to_fit(self, width, height, padding=0, step=5):
|
||||||
|
drawings = []
|
||||||
|
width -= padding * 2
|
||||||
|
height -= padding * 2
|
||||||
|
for angle in range(0, 180, step):
|
||||||
|
drawing = self.rotate(angle)
|
||||||
|
scale = min(width / drawing.width, height / drawing.height)
|
||||||
|
drawings.append((scale, drawing))
|
||||||
|
scale, drawing = max(drawings)
|
||||||
|
return drawing.scale(scale, scale).origin()
|
|
@ -12,7 +12,7 @@ def circle(cx, cy, r, n):
|
||||||
return points
|
return points
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
planner = Planner(acceleration=10, max_velocity=5, corner_factor=0.01)
|
planner = Planner(acceleration=10, max_velocity=5, corner_factor=0.001)
|
||||||
path = []
|
path = []
|
||||||
path.append((0, 0))
|
path.append((0, 0))
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue