PEP 8 intentation

main
jebba 2022-01-15 13:41:38 -07:00
parent e0bac6471f
commit 8f6059669d
6 changed files with 1009 additions and 1009 deletions

180
layer.py
View File

@ -5,105 +5,105 @@
import math, mymath
class Layer():
def __init__(self, dimensions, scale):
self.width, self.height = dimensions
self.scale = scale
self.buckets = [[] for x in range(self.width * self.height)]
self.test = 0
def __init__(self, dimensions, scale):
self.width, self.height = dimensions
self.scale = scale
self.buckets = [[] for x in range(self.width * self.height)]
self.test = 0
def aabb(self, line):
x1, y1, x2, y2, r, g = line
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
r += g
minx = int(math.floor((x1 - r) * self.scale))
miny = int(math.floor((y1 - r) * self.scale))
maxx = int(math.ceil((x2 + r) * self.scale))
maxy = int(math.ceil((y2 + r) * self.scale))
if minx < 0:
minx = 0
if miny < 0:
miny = 0
if maxx > self.width:
maxx = self.width
if maxy > self.height:
maxy = self.height
return (minx, miny, maxx, maxy)
def aabb(self, line):
x1, y1, x2, y2, r, g = line
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
r += g
minx = int(math.floor((x1 - r) * self.scale))
miny = int(math.floor((y1 - r) * self.scale))
maxx = int(math.ceil((x2 + r) * self.scale))
maxy = int(math.ceil((y2 + r) * self.scale))
if minx < 0:
minx = 0
if miny < 0:
miny = 0
if maxx > self.width:
maxx = self.width
if maxy > self.height:
maxy = self.height
return (minx, miny, maxx, maxy)
def all_buckets(self, aabb):
x1, y1, x2, y2 = aabb
for y in range(y1, y2):
for x in range(x1, x2):
yield self.buckets[y * self.width + x]
def all_buckets(self, aabb):
x1, y1, x2, y2 = aabb
for y in range(y1, y2):
for x in range(x1, x2):
yield self.buckets[y * self.width + x]
def all_not_empty_buckets(self, aabb):
x1, y1, x2, y2 = aabb
for y in range(y1, y2):
for x in range(x1, x2):
bucket = self.buckets[y * self.width + x]
if bucket:
yield bucket
def all_not_empty_buckets(self, aabb):
x1, y1, x2, y2 = aabb
for y in range(y1, y2):
for x in range(x1, x2):
bucket = self.buckets[y * self.width + x]
if bucket:
yield bucket
def add_line(self, line):
new_record = [0, line]
for bucket in self.all_buckets(self.aabb(line)):
found = False
for record in bucket:
if record[1] == line:
found = True
break
if not found:
bucket.append(new_record)
def add_line(self, line):
new_record = [0, line]
for bucket in self.all_buckets(self.aabb(line)):
found = False
for record in bucket:
if record[1] == line:
found = True
break
if not found:
bucket.append(new_record)
def sub_line(self, line):
for bucket in self.all_not_empty_buckets(self.aabb(line)):
for i in range(len(bucket) - 1, -1, -1):
if bucket[i][1] == line:
del bucket[i]
def sub_line(self, line):
for bucket in self.all_not_empty_buckets(self.aabb(line)):
for i in range(len(bucket) - 1, -1, -1):
if bucket[i][1] == line:
del bucket[i]
def hit_line(self, line):
self.test += 1
for bucket in self.all_not_empty_buckets(self.aabb(line)):
for record in bucket:
if record[0] != self.test:
record[0] = self.test
l1_p1x, l1_p1y, l1_p2x, l1_p2y, l1_r, l1_g = line
l2_p1x, l2_p1y, l2_p2x, l2_p2y, l2_r, l2_g = record[1]
r = l1_r + l2_r + max(l1_g, l2_g)
if mymath.collide_thick_lines_2d((l1_p1x, l1_p1y), (l1_p2x, l1_p2y), (l2_p1x, l2_p1y), (l2_p2x, l2_p2y), r):
return True
return False
def hit_line(self, line):
self.test += 1
for bucket in self.all_not_empty_buckets(self.aabb(line)):
for record in bucket:
if record[0] != self.test:
record[0] = self.test
l1_p1x, l1_p1y, l1_p2x, l1_p2y, l1_r, l1_g = line
l2_p1x, l2_p1y, l2_p2x, l2_p2y, l2_r, l2_g = record[1]
r = l1_r + l2_r + max(l1_g, l2_g)
if mymath.collide_thick_lines_2d((l1_p1x, l1_p1y), (l1_p2x, l1_p2y), (l2_p1x, l2_p1y), (l2_p2x, l2_p2y), r):
return True
return False
class Layers():
def __init__(self, dimensions, scale):
width, height, self.depth = dimensions
self.layers = [Layer((width, height), scale) for z in range(self.depth)]
def __init__(self, dimensions, scale):
width, height, self.depth = dimensions
self.layers = [Layer((width, height), scale) for z in range(self.depth)]
def all_layers(self, z1, z2):
if z1 != z2:
for z in range(self.depth):
yield self.layers[z]
else:
yield self.layers[int(z1)]
def all_layers(self, z1, z2):
if z1 != z2:
for z in range(self.depth):
yield self.layers[z]
else:
yield self.layers[int(z1)]
def add_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
layer.add_line((x1, y1, x2, y2, r, g))
def add_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
layer.add_line((x1, y1, x2, y2, r, g))
def sub_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
layer.sub_line((x1, y1, x2, y2, r, g))
def sub_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
layer.sub_line((x1, y1, x2, y2, r, g))
def hit_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
if layer.hit_line((x1, y1, x2, y2, r, g)):
return True
return False
def hit_line(self, p1, p2, r, g):
x1, y1, z1 = p1
x2, y2, z2 = p2
for layer in self.all_layers(z1, z2):
if layer.hit_line((x1, y1, x2, y2, r, g)):
return True
return False

478
mymath.py
View File

@ -7,332 +7,332 @@ import math, random, itertools
#generic distance metric stuff
def manhattan_distance(p1, p2):
return sum(abs(x - y) for x, y in zip(p1, p2))
return sum(abs(x - y) for x, y in zip(p1, p2))
def euclidean_distance(p1, p2):
return math.sqrt(sum((x - y) ** 2 for x, y in zip(p1, p2)))
return math.sqrt(sum((x - y) ** 2 for x, y in zip(p1, p2)))
def squared_euclidean_distance(p1, p2):
return sum((x - y) ** 2 for x, y in zip(p1, p2))
return sum((x - y) ** 2 for x, y in zip(p1, p2))
def chebyshev_distance(p1, p2):
return max(abs(x - y) for x, y in zip(p1, p2))
return max(abs(x - y) for x, y in zip(p1, p2))
def reciprical_distance(p1, p2):
d = manhattan_distance(p1, p2)
return 1.0 / d if d != 0 else 1.0
d = manhattan_distance(p1, p2)
return 1.0 / d if d != 0 else 1.0
def random_distance(p1, p2):
return random.random()
return random.random()
#generic vector stuff
def sign(x):
if x == 0:
return 0
if x < 0:
return -1
return 1
if x == 0:
return 0
if x < 0:
return -1
return 1
def equal(p1, p2):
return manhattan_distance(p1, p2) == 0.0
return manhattan_distance(p1, p2) == 0.0
def add(p1, p2):
return tuple(x + y for x, y in zip(p1, p2))
return tuple(x + y for x, y in zip(p1, p2))
def sub(p1, p2):
return tuple(x - y for x, y in zip(p1, p2))
return tuple(x - y for x, y in zip(p1, p2))
def scale(p, s):
return tuple(x * s for x in p)
return tuple(x * s for x in p)
def dot(p1, p2):
return sum(x * y for x, y in zip(p1, p2))
return sum(x * y for x, y in zip(p1, p2))
def length(p):
return math.sqrt(dot(p, p))
return math.sqrt(dot(p, p))
def distance(p1, p2):
return length(sub(p2, p1))
return length(sub(p2, p1))
def distance_squared(p1, p2):
p = sub(p2, p1)
return dot(p, p)
p = sub(p2, p1)
return dot(p, p)
def norm(p):
l = length(p)
if l == 0:
return scale(p, 0)
l = 1.0 / l
return scale(p, l)
l = length(p)
if l == 0:
return scale(p, 0)
l = 1.0 / l
return scale(p, l)
def distance_to_line(p, p1, p2):
lv = sub(p2, p1)
pv = sub(p, p1)
c1 = dot(pv, lv)
if c1 <= 0:
return distance(p, p1)
c2 = dot(lv, lv)
if c2 <= c1:
return distance(p, p2)
return distance(p, add(p1, scale(lv, c1 / float(c2))))
lv = sub(p2, p1)
pv = sub(p, p1)
c1 = dot(pv, lv)
if c1 <= 0:
return distance(p, p1)
c2 = dot(lv, lv)
if c2 <= c1:
return distance(p, p2)
return distance(p, add(p1, scale(lv, c1 / float(c2))))
def distance_squared_to_line(p, p1, p2):
lv = sub(p2, p1)
pv = sub(p, p1)
c1 = dot(pv, lv)
if c1 <= 0:
return distance_squared(p, p1)
c2 = dot(lv, lv)
if c2 <= c1:
return distance_squared(p, p2)
return distance_squared(p, add(p1, scale(lv, c1 / float(c2))))
lv = sub(p2, p1)
pv = sub(p, p1)
c1 = dot(pv, lv)
if c1 <= 0:
return distance_squared(p, p1)
c2 = dot(lv, lv)
if c2 <= c1:
return distance_squared(p, p2)
return distance_squared(p, add(p1, scale(lv, c1 / float(c2))))
#specific vector stuff
def add_2d(p1, p2):
x1, y1 = p1
x2, y2 = p2
return x1 + x2, y1 + y2
x1, y1 = p1
x2, y2 = p2
return x1 + x2, y1 + y2
def add_3d(p1, p2):
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 + x2, y1 + y2, z1 + z2
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 + x2, y1 + y2, z1 + z2
def sub_2d(p1, p2):
x1, y1 = p1
x2, y2 = p2
return x1 - x2, y1 - y2
x1, y1 = p1
x2, y2 = p2
return x1 - x2, y1 - y2
def sub_3d(p1, p2):
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 - x2, y1 - y2, z1 - z2
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 - x2, y1 - y2, z1 - z2
def scale_2d(p, s):
x, y = p
return x * s, y * s
x, y = p
return x * s, y * s
def scale_3d(p, s):
x, y, z = p
return x * s, y * s, z * s
x, y, z = p
return x * s, y * s, z * s
def perp_2d(p):
x, y = p
return y, -x
x, y = p
return y, -x
def cross_3d(p1, p2):
x1, y1, z1 = p1
x2, y2, z2 = p2
return (y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2)
x1, y1, z1 = p1
x2, y2, z2 = p2
return (y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2)
def dot_2d(p1, p2):
x1, y1 = p1
x2, y2 = p2
return x1 * x2 + y1 * y2
x1, y1 = p1
x2, y2 = p2
return x1 * x2 + y1 * y2
def dot_3d(p1, p2):
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 * x2 + y1 * y2 + z1 * z2
x1, y1, z1 = p1
x2, y2, z2 = p2
return x1 * x2 + y1 * y2 + z1 * z2
def length_2d(p):
return math.sqrt(dot_2d(p, p))
return math.sqrt(dot_2d(p, p))
def length_3d(p):
return math.sqrt(dot_3d(p, p))
return math.sqrt(dot_3d(p, p))
def norm_2d(p):
l = length_2d(p)
if l == 0:
return (0, 0)
x, y = p
return (x / l, y / l)
l = length_2d(p)
if l == 0:
return (0, 0)
x, y = p
return (x / l, y / l)
def norm_3d(p):
l = length_3d(p)
if l == 0:
return (0, 0, 0)
x, y, z = p
return (x / l, y / l, z / l)
l = length_3d(p)
if l == 0:
return (0, 0, 0)
x, y, z = p
return (x / l, y / l, z / l)
def distance_2d(p1, p2):
return length_2d(sub_2d(p2 - p1))
return length_2d(sub_2d(p2 - p1))
def distance_3d(p1, p2):
return length_3d(sub_3d(p2 - p1))
return length_3d(sub_3d(p2 - p1))
def distance_squared_2d(p1, p2):
x1, y1 = p1
x2, y2 = p2
p = x2 - x1, y2 - y1
return dot_2d(p, p)
x1, y1 = p1
x2, y2 = p2
p = x2 - x1, y2 - y1
return dot_2d(p, p)
def distance_squared_3d(p1, p2):
x1, y1, z1 = p1
x2, y2, z2 = p2
p = x2 - x1, y2 - y1, z2 - z1
return dot_3d(p, p)
x1, y1, z1 = p1
x2, y2, z2 = p2
p = x2 - x1, y2 - y1, z2 - z1
return dot_3d(p, p)
def distance_to_line_2d(p, p1, p2):
lv = sub_2d(p2, p1)
pv = sub_2d(p, p1)
c1 = dot_2d(pv, lv)
if c1 <= 0:
return distance_2d(p, p1)
c2 = dot_2d(lv, lv)
if c2 <= c1:
return distance_2d(p, p2)
return distance_2d(p, add_2d(p1, scale_2d(lv, c1 / float(c2))))
lv = sub_2d(p2, p1)
pv = sub_2d(p, p1)
c1 = dot_2d(pv, lv)
if c1 <= 0:
return distance_2d(p, p1)
c2 = dot_2d(lv, lv)
if c2 <= c1:
return distance_2d(p, p2)
return distance_2d(p, add_2d(p1, scale_2d(lv, c1 / float(c2))))
def distance_to_line_3d(p, p1, p2):
lv = sub_3d(p2, p1)
pv = sub_3d(p, p1)
c1 = dot_3d(pv, lv)
if c1 <= 0:
return distance_3d(p, p1)
c2 = dot_3d(lv, lv)
if c2 <= c1:
return distance_3d(p, p2)
return distance_3d(p, add_3d(p1, scale_3d(lv, c1 / float(c2))))
lv = sub_3d(p2, p1)
pv = sub_3d(p, p1)
c1 = dot_3d(pv, lv)
if c1 <= 0:
return distance_3d(p, p1)
c2 = dot_3d(lv, lv)
if c2 <= c1:
return distance_3d(p, p2)
return distance_3d(p, add_3d(p1, scale_3d(lv, c1 / float(c2))))
def distance_squared_to_line_2d(p, p1, p2):
lv = sub_2d(p2, p1)
pv = sub_2d(p, p1)
c1 = dot_2d(pv, lv)
if c1 <= 0:
return distance_squared_2d(p, p1)
c2 = dot_2d(lv, lv)
if c2 <= c1:
return distance_squared_2d(p, p2)
return distance_squared_2d(p, add_2d(p1, scale_2d(lv, c1 / float(c2))))
lv = sub_2d(p2, p1)
pv = sub_2d(p, p1)
c1 = dot_2d(pv, lv)
if c1 <= 0:
return distance_squared_2d(p, p1)
c2 = dot_2d(lv, lv)
if c2 <= c1:
return distance_squared_2d(p, p2)
return distance_squared_2d(p, add_2d(p1, scale_2d(lv, c1 / float(c2))))
def distance_squared_to_line_3d(p, p1, p2):
lv = sub_3d(p2, p1)
pv = sub_3d(p, p1)
c1 = dot_3d(pv, lv)
if c1 <= 0:
return distance_squared_3d(p, p1)
c2 = dot_3d(lv, lv)
if c2 <= c1:
return distance_squared_3d(p, p2)
return distance_squared_3d(p, add_3d(p1, scale_3d(lv, c1 / float(c2))))
lv = sub_3d(p2, p1)
pv = sub_3d(p, p1)
c1 = dot_3d(pv, lv)
if c1 <= 0:
return distance_squared_3d(p, p1)
c2 = dot_3d(lv, lv)
if c2 <= c1:
return distance_squared_3d(p, p2)
return distance_squared_3d(p, add_3d(p1, scale_3d(lv, c1 / float(c2))))
def collide_lines_2d(l1_p1, l1_p2, l2_p1, l2_p2):
l1_x1, l1_y1 = l1_p1
l1_x2, l1_y2 = l1_p2
l2_x1, l2_y1 = l2_p1
l2_x2, l2_y2 = l2_p2
ax = l1_x2 - l1_x1
ay = l1_y2 - l1_y1
bx = l2_x1 - l2_x2
by = l2_y1 - l2_y2
cx = l1_x1 - l2_x1
cy = l1_y1 - l2_y1
an = by * cx - bx * cy
ad = ay * bx - ax * by
bn = ax * cy - ay * cx
bd = ay * bx - ax * by
if (ad == 0 or bd == 0):
return False
else:
if (ad > 0):
if (an < 0 or an > ad):
return False
else:
if (an > 0 or an < ad):
return False;
if (bd > 0):
if (bn < 0 or bn > bd):
return False
else:
if (bn > 0 or bn < bd):
return False
return True
l1_x1, l1_y1 = l1_p1
l1_x2, l1_y2 = l1_p2
l2_x1, l2_y1 = l2_p1
l2_x2, l2_y2 = l2_p2
ax = l1_x2 - l1_x1
ay = l1_y2 - l1_y1
bx = l2_x1 - l2_x2
by = l2_y1 - l2_y2
cx = l1_x1 - l2_x1
cy = l1_y1 - l2_y1
an = by * cx - bx * cy
ad = ay * bx - ax * by
bn = ax * cy - ay * cx
bd = ay * bx - ax * by
if (ad == 0 or bd == 0):
return False
else:
if (ad > 0):
if (an < 0 or an > ad):
return False
else:
if (an > 0 or an < ad):
return False;
if (bd > 0):
if (bn < 0 or bn > bd):
return False
else:
if (bn > 0 or bn < bd):
return False
return True
def collide_thick_lines_2d(tl1_p1, tl1_p2, tl2_p1, tl2_p2, r):
if collide_lines_2d(tl1_p1, tl1_p2, tl2_p1, tl2_p2):
return True
r *= r
if distance_squared_to_line_2d(tl2_p1, tl1_p1, tl1_p2) <= r:
return True
if distance_squared_to_line_2d(tl2_p2, tl1_p1, tl1_p2) <= r:
return True
if distance_squared_to_line_2d(tl1_p1, tl2_p1, tl2_p2) <= r:
return True
if distance_squared_to_line_2d(tl1_p2, tl2_p1, tl2_p2) <= r:
return True
return False
if collide_lines_2d(tl1_p1, tl1_p2, tl2_p1, tl2_p2):
return True
r *= r
if distance_squared_to_line_2d(tl2_p1, tl1_p1, tl1_p2) <= r:
return True
if distance_squared_to_line_2d(tl2_p2, tl1_p1, tl1_p2) <= r:
return True
if distance_squared_to_line_2d(tl1_p1, tl2_p1, tl2_p2) <= r:
return True
if distance_squared_to_line_2d(tl1_p2, tl2_p1, tl2_p2) <= r:
return True
return False
#generic path stuff
def thicken_path_2d(points, radius, capstyle, joinstyle):
if radius == 0:
return points[:] + points[::-1]
index = 0
step = 1
out_points = []
resolution = int(math.pi * radius) + 1
while True:
p1 = points[index]; index += step
p2 = points[index]; index += step
l2_v = sub_2d(p2, p1)
l2_pv = perp_2d(l2_v)
l2_npv = norm_2d(l2_pv)
rv = scale_2d(l2_npv, radius)
if capstyle == 0:
#butt cap
out_points.append(sub_2d(p1, rv))
out_points.append(add_2d(p1, rv))
elif capstyle == 1:
#square cap
p0 = add_2d(p1, perp_2d(rv))
out_points.append(sub_2d(p0, rv))
out_points.append(add_2d(p0, rv))
elif capstyle == 2:
#triangle cap
out_points.append(sub_2d(p1, rv))
out_points.append(add_2d(p1, perp_2d(rv)))
out_points.append(add_2d(p1, rv))
elif capstyle == 3:
#round cap
rvx, rvy = rv
for i in range(resolution + 1):
angle = (i * math.pi) / resolution
s = math.sin(angle)
c = math.cos(angle)
rv = rvx * c - rvy * s, rvx * s + rvy * c
out_points.append(sub_2d(p1, rv))
while index != -1 and index != len(points):
p1, l1_v, l1_npv = p2, l2_v, l2_npv
p2 = points[index]; index += step
l2_v = sub_2d(p2, p1)
l2_pv = perp_2d(l2_v)
l2_npv = norm_2d(l2_pv)
nbv = norm_2d(scale_2d(add_2d(l1_npv, l2_npv), 0.5))
c = dot_2d(nbv, norm_2d(l1_v))
if c <= 0 or joinstyle == 0:
#mitre join
s = math.sin(math.acos(c))
bv = scale_2d(nbv, radius / s)
out_points.append(add_2d(p1, bv))
elif joinstyle == 1:
#bevel join
out_points.append(add_2d(p1, scale_2d(l1_npv, radius)))
out_points.append(add_2d(p1, scale_2d(l2_npv, radius)))
elif joinstyle == 2:
#round join
rvx, rvy = scale_2d(l1_npv, radius)
theta = math.acos(dot_2d(l1_npv, l2_npv))
segs = int((theta / math.pi) * resolution) + 1
for i in range(segs + 1):
angle = (i * theta) / segs
s = math.sin(angle)
c = math.cos(angle)
rv = rvx * c - rvy * s, rvx * s + rvy * c
out_points.append(add_2d(p1, rv))
if step < 0:
break
step = -step; index += step
return out_points
if radius == 0:
return points[:] + points[::-1]
index = 0
step = 1
out_points = []
resolution = int(math.pi * radius) + 1
while True:
p1 = points[index]; index += step
p2 = points[index]; index += step
l2_v = sub_2d(p2, p1)
l2_pv = perp_2d(l2_v)
l2_npv = norm_2d(l2_pv)
rv = scale_2d(l2_npv, radius)
if capstyle == 0:
#butt cap
out_points.append(sub_2d(p1, rv))
out_points.append(add_2d(p1, rv))
elif capstyle == 1:
#square cap
p0 = add_2d(p1, perp_2d(rv))
out_points.append(sub_2d(p0, rv))
out_points.append(add_2d(p0, rv))
elif capstyle == 2:
#triangle cap
out_points.append(sub_2d(p1, rv))
out_points.append(add_2d(p1, perp_2d(rv)))
out_points.append(add_2d(p1, rv))
elif capstyle == 3:
#round cap
rvx, rvy = rv
for i in range(resolution + 1):
angle = (i * math.pi) / resolution
s = math.sin(angle)
c = math.cos(angle)
rv = rvx * c - rvy * s, rvx * s + rvy * c
out_points.append(sub_2d(p1, rv))
while index != -1 and index != len(points):
p1, l1_v, l1_npv = p2, l2_v, l2_npv
p2 = points[index]; index += step
l2_v = sub_2d(p2, p1)
l2_pv = perp_2d(l2_v)
l2_npv = norm_2d(l2_pv)
nbv = norm_2d(scale_2d(add_2d(l1_npv, l2_npv), 0.5))
c = dot_2d(nbv, norm_2d(l1_v))
if c <= 0 or joinstyle == 0:
#mitre join
s = math.sin(math.acos(c))
bv = scale_2d(nbv, radius / s)
out_points.append(add_2d(p1, bv))
elif joinstyle == 1:
#bevel join
out_points.append(add_2d(p1, scale_2d(l1_npv, radius)))
out_points.append(add_2d(p1, scale_2d(l2_npv, radius)))
elif joinstyle == 2:
#round join
rvx, rvy = scale_2d(l1_npv, radius)
theta = math.acos(dot_2d(l1_npv, l2_npv))
segs = int((theta / math.pi) * resolution) + 1
for i in range(segs + 1):
angle = (i * theta) / segs
s = math.sin(angle)
c = math.cos(angle)
rv = rvx * c - rvy * s, rvx * s + rvy * c
out_points.append(add_2d(p1, rv))
if step < 0:
break
step = -step; index += step
return out_points

112
pcb.py
View File

@ -9,67 +9,67 @@ from ast import literal_eval
from mymath import *
def main():
parser = argparse.ArgumentParser(description = 'Pcb layout optimizer.', formatter_class = argparse.RawTextHelpFormatter)
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--t', nargs = 1, type = int, default = [600], help = 'timeout in seconds, default 600')
parser.add_argument('--v', nargs = 1, type = int, default = [0], choices = range(0, 2), help = 'verbosity level 0..1, default 0')
parser.add_argument('--s', nargs = 1, type = int, default = [1], help = 'number of samples, default 1')
parser.add_argument('--r', nargs = 1, type = int, default = [1], choices = range(1, 5), help = 'grid resolution 1..4, default 1')
parser.add_argument('--z', nargs = 1, type = int, default = [0], choices = range(0, 2), help = 'minimize vias 0..1, default 0')
parser.add_argument('--d', nargs = 1, type = int, default = [0], choices = range(0, 6), \
help = 'distance metric 0..5, default 0.\n' \
'0 -> manhattan\n1 -> squared_euclidean\n2 -> euclidean\n3 -> chebyshev\n4 -> reciprocal\n5 -> random')
parser.add_argument('--fr', nargs = 1, type = int, default = [2], choices = range(1, 6), help = 'flood range 1..5, default 2')
parser.add_argument('--xr', nargs = 1, type = int, default = [1], choices = range(0, 6), help = 'even layer x range 0..5, default 1')
parser.add_argument('--yr', nargs = 1, type = int, default = [1], choices = range(0, 6), help = 'odd layer y range 0..5, default 1')
args = parser.parse_args()
parser = argparse.ArgumentParser(description = 'Pcb layout optimizer.', formatter_class = argparse.RawTextHelpFormatter)
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--t', nargs = 1, type = int, default = [600], help = 'timeout in seconds, default 600')
parser.add_argument('--v', nargs = 1, type = int, default = [0], choices = range(0, 2), help = 'verbosity level 0..1, default 0')
parser.add_argument('--s', nargs = 1, type = int, default = [1], help = 'number of samples, default 1')
parser.add_argument('--r', nargs = 1, type = int, default = [1], choices = range(1, 5), help = 'grid resolution 1..4, default 1')
parser.add_argument('--z', nargs = 1, type = int, default = [0], choices = range(0, 2), help = 'minimize vias 0..1, default 0')
parser.add_argument('--d', nargs = 1, type = int, default = [0], choices = range(0, 6), \
help = 'distance metric 0..5, default 0.\n' \
'0 -> manhattan\n1 -> squared_euclidean\n2 -> euclidean\n3 -> chebyshev\n4 -> reciprocal\n5 -> random')
parser.add_argument('--fr', nargs = 1, type = int, default = [2], choices = range(1, 6), help = 'flood range 1..5, default 2')
parser.add_argument('--xr', nargs = 1, type = int, default = [1], choices = range(0, 6), help = 'even layer x range 0..5, default 1')
parser.add_argument('--yr', nargs = 1, type = int, default = [1], choices = range(0, 6), help = 'odd layer y range 0..5, default 1')
args = parser.parse_args()
flood_range = args.fr[0]
flood_range_x_even_layer = args.xr[0]
flood_range_y_odd_layer = args.yr[0]
path_range = flood_range + 0
path_range_x_even_layer = flood_range_x_even_layer + 0
path_range_y_odd_layer = flood_range_y_odd_layer + 0
flood_range = args.fr[0]
flood_range_x_even_layer = args.xr[0]
flood_range_y_odd_layer = args.yr[0]
path_range = flood_range + 0
path_range_x_even_layer = flood_range_x_even_layer + 0
path_range_y_odd_layer = flood_range_y_odd_layer + 0
routing_flood_vectors = [[(x, y, 0) for x in range(-flood_range_x_even_layer, flood_range_x_even_layer + 1) for y in range(-flood_range, flood_range + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= flood_range] + [(0, 0, -1), (0, 0, 1)], \
[(x, y, 0) for x in range(-flood_range, flood_range + 1) for y in range(-flood_range_y_odd_layer, flood_range_y_odd_layer + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= flood_range] + [(0, 0, -1), (0, 0, 1)]]
routing_flood_vectors = [[(x, y, 0) for x in range(-flood_range_x_even_layer, flood_range_x_even_layer + 1) for y in range(-flood_range, flood_range + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= flood_range] + [(0, 0, -1), (0, 0, 1)], \
[(x, y, 0) for x in range(-flood_range, flood_range + 1) for y in range(-flood_range_y_odd_layer, flood_range_y_odd_layer + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= flood_range] + [(0, 0, -1), (0, 0, 1)]]
routing_path_vectors = [[(x, y, 0) for x in range(-path_range_x_even_layer, path_range_x_even_layer + 1) for y in range(-path_range, path_range + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= path_range] + [(0, 0, -1), (0, 0, 1)], \
[(x, y, 0) for x in range(-path_range, path_range + 1) for y in range(-path_range_y_odd_layer, path_range_y_odd_layer + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= path_range] + [(0, 0, -1), (0, 0, 1)]]
routing_path_vectors = [[(x, y, 0) for x in range(-path_range_x_even_layer, path_range_x_even_layer + 1) for y in range(-path_range, path_range + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= path_range] + [(0, 0, -1), (0, 0, 1)], \
[(x, y, 0) for x in range(-path_range, path_range + 1) for y in range(-path_range_y_odd_layer, path_range_y_odd_layer + 1) \
if length_2d((x, y)) > 0.1 and length_2d((x, y)) <= path_range] + [(0, 0, -1), (0, 0, 1)]]
dfunc = [manhattan_distance, squared_euclidean_distance, euclidean_distance, \
chebyshev_distance, reciprical_distance, random_distance][args.d[0]]
dfunc = [manhattan_distance, squared_euclidean_distance, euclidean_distance, \
chebyshev_distance, reciprical_distance, random_distance][args.d[0]]
dimensions = literal_eval(args.infile.readline().strip())
pcb = router.Pcb(dimensions, routing_flood_vectors, routing_path_vectors, dfunc, args.r[0], args.v[0], args.z[0])
for line in args.infile:
track = literal_eval(line.strip())
if not track:
break
pcb.add_track(track)
args.infile.close()
dimensions = literal_eval(args.infile.readline().strip())
pcb = router.Pcb(dimensions, routing_flood_vectors, routing_path_vectors, dfunc, args.r[0], args.v[0], args.z[0])
for line in args.infile:
track = literal_eval(line.strip())
if not track:
break
pcb.add_track(track)
args.infile.close()
pcb.print_pcb()
best_cost = None
best_pcb = None
for i in range(args.s[0]):
if not pcb.route(args.t[0]):
pcb.shuffle_netlist()
continue
cost = pcb.cost()
if best_cost == None or cost < best_cost:
best_cost = cost
best_pcb = deepcopy(pcb)
pcb.shuffle_netlist()
if best_pcb != None:
best_pcb.print_netlist()
best_pcb.print_stats()
else:
print([])
pcb.print_pcb()
best_cost = None
best_pcb = None
for i in range(args.s[0]):
if not pcb.route(args.t[0]):
pcb.shuffle_netlist()
continue
cost = pcb.cost()
if best_cost == None or cost < best_cost:
best_cost = cost
best_pcb = deepcopy(pcb)
pcb.shuffle_netlist()
if best_pcb != None:
best_pcb.print_netlist()
best_pcb.print_stats()
else:
print([])
if __name__ == '__main__':
main()
main()

510
router.py
View File

@ -10,289 +10,289 @@ from mymath import *
from layer import *
def shift(l, n):
n = n % len(l)
head = l[:n]
del l[:n]
l.extend(head)
return l
n = n % len(l)
head = l[:n]
del l[:n]
l.extend(head)
return l
class Pcb():
def __init__(self, dimensions, routing_flood_vectors, routing_path_vectors, dfunc, resolution, verbosity, minz):
self.dfunc = dfunc
self.verbosity = verbosity
self.routing_flood_vectors = routing_flood_vectors
self.routing_path_vectors = routing_path_vectors
self.layers = Layers(dimensions, 1.0 / resolution)
self.width, self.height, self.depth = dimensions
self.resolution = resolution
self.minz = minz
self.width *= resolution
self.height *= resolution
self.stride = self.width * self.height
self.nodes = array('i', [0 for x in range(self.stride * self.depth)])
self.netlist = []
self.deform = {}
def __init__(self, dimensions, routing_flood_vectors, routing_path_vectors, dfunc, resolution, verbosity, minz):
self.dfunc = dfunc
self.verbosity = verbosity
self.routing_flood_vectors = routing_flood_vectors
self.routing_path_vectors = routing_path_vectors
self.layers = Layers(dimensions, 1.0 / resolution)
self.width, self.height, self.depth = dimensions
self.resolution = resolution
self.minz = minz
self.width *= resolution
self.height *= resolution
self.stride = self.width * self.height
self.nodes = array('i', [0 for x in range(self.stride * self.depth)])
self.netlist = []
self.deform = {}
def grid_to_space_point(self, node):
if node in self.deform:
return self.deform[node]
return (float(node[0]), float(node[1]), float(node[2]))
def grid_to_space_point(self, node):
if node in self.deform:
return self.deform[node]
return (float(node[0]), float(node[1]), float(node[2]))
def set_node(self, node, value):
self.nodes[(self.stride * node[2]) + (node[1] * self.width) + node[0]] = value
def set_node(self, node, value):
self.nodes[(self.stride * node[2]) + (node[1] * self.width) + node[0]] = value
def get_node(self, node):
return self.nodes[(self.stride * node[2]) + (node[1] * self.width) + node[0]]
def get_node(self, node):
return self.nodes[(self.stride * node[2]) + (node[1] * self.width) + node[0]]
def all_marked(self, vectors, node):
x, y, z = node
for dx, dy, dz in vectors[z % 2]:
nx = x + dx; ny = y + dy; nz = z + dz
if (0 <= nx < self.width) and (0 <= ny < self.height) and (0 <= nz < self.depth):
mark = self.get_node((nx, ny, nz))
if mark != 0:
yield (mark, (nx, ny, nz))
def all_marked(self, vectors, node):
x, y, z = node
for dx, dy, dz in vectors[z % 2]:
nx = x + dx; ny = y + dy; nz = z + dz
if (0 <= nx < self.width) and (0 <= ny < self.height) and (0 <= nz < self.depth):
mark = self.get_node((nx, ny, nz))
if mark != 0:
yield (mark, (nx, ny, nz))
def all_not_marked(self, vectors, node):
x, y, z = node
for dx, dy, dz in vectors[z % 2]:
nx = x + dx; ny = y + dy; nz = z + dz
if (0 <= nx < self.width) and (0 <= ny < self.height) and (0 <= nz < self.depth):
if self.get_node((nx, ny, nz)) == 0:
yield (nx, ny, nz)
def all_not_marked(self, vectors, node):
x, y, z = node
for dx, dy, dz in vectors[z % 2]:
nx = x + dx; ny = y + dy; nz = z + dz
if (0 <= nx < self.width) and (0 <= ny < self.height) and (0 <= nz < self.depth):
if self.get_node((nx, ny, nz)) == 0:
yield (nx, ny, nz)
def all_nearer_sorted(self, vectors, node, goal, func):
distance = self.get_node(node)
sgoal = self.grid_to_space_point(goal)
nodes = [(func(self.grid_to_space_point(marked[1]), sgoal), marked[1]) \
for marked in self.all_marked(vectors, node) \
if (distance - marked[0]) > 0]
nodes.sort()
for node in nodes:
yield node[1]
def all_nearer_sorted(self, vectors, node, goal, func):
distance = self.get_node(node)
sgoal = self.grid_to_space_point(goal)
nodes = [(func(self.grid_to_space_point(marked[1]), sgoal), marked[1]) \
for marked in self.all_marked(vectors, node) \
if (distance - marked[0]) > 0]
nodes.sort()
for node in nodes:
yield node[1]
def all_not_shorting(self, gather, params, node, radius, via, gap):
np = self.grid_to_space_point(node)
for new_node in gather(*params):
nnp = self.grid_to_space_point(new_node)
if node[2] != new_node[2]:
if not self.layers.hit_line(np, nnp, via, gap):
yield new_node
else:
if not self.layers.hit_line(np, nnp, radius, gap):
yield new_node
def all_not_shorting(self, gather, params, node, radius, via, gap):
np = self.grid_to_space_point(node)
for new_node in gather(*params):
nnp = self.grid_to_space_point(new_node)
if node[2] != new_node[2]:
if not self.layers.hit_line(np, nnp, via, gap):
yield new_node
else:
if not self.layers.hit_line(np, nnp, radius, gap):
yield new_node
def mark_distances(self, vectors, radius, via, gap, starts, ends = []):
distance = 1
nodes = list(starts)
for node in nodes:
self.set_node(node, distance)
while nodes:
distance += 1
new_nodes = []
for node in nodes:
for new_node in self.all_not_shorting(self.all_not_marked, (vectors, node), node, radius, via, gap):
self.set_node(new_node, distance)
new_nodes.append(new_node)
nodes = new_nodes
if 0 not in [self.get_node(node) for node in ends]:
break
def mark_distances(self, vectors, radius, via, gap, starts, ends = []):
distance = 1
nodes = list(starts)
for node in nodes:
self.set_node(node, distance)
while nodes:
distance += 1
new_nodes = []
for node in nodes:
for new_node in self.all_not_shorting(self.all_not_marked, (vectors, node), node, radius, via, gap):
self.set_node(new_node, distance)
new_nodes.append(new_node)
nodes = new_nodes
if 0 not in [self.get_node(node) for node in ends]:
break
def unmark_distances(self):
self.nodes = array('i', [0 for x in range(self.stride * self.depth)])
def unmark_distances(self):
self.nodes = array('i', [0 for x in range(self.stride * self.depth)])
def add_track(self, track):
radius, via, gap, net = track
self.netlist.append(Net(net, radius, via, gap, self))
def add_track(self, track):
radius, via, gap, net = track
self.netlist.append(Net(net, radius, via, gap, self))
def route(self, timeout):
self.remove_netlist()
self.unmark_distances()
now = time.time()
self.netlist.sort(key = lambda i: i.radius, reverse = True)
index = 0
while index < len(self.netlist):
if self.netlist[index].route(self.minz):
index += 1
else:
if index == 0:
self.shuffle_netlist()
else:
self.netlist.insert(0, self.netlist.pop(index))
while index != 0:
self.netlist[index].remove()
self.netlist[index].shuffle_topology()
index -= 1
if time.time() - now > timeout:
return False
if self.verbosity >= 1:
self.print_netlist()
return True
def route(self, timeout):
self.remove_netlist()
self.unmark_distances()
now = time.time()
self.netlist.sort(key = lambda i: i.radius, reverse = True)
index = 0
while index < len(self.netlist):
if self.netlist[index].route(self.minz):
index += 1
else:
if index == 0:
self.shuffle_netlist()
else:
self.netlist.insert(0, self.netlist.pop(index))
while index != 0:
self.netlist[index].remove()
self.netlist[index].shuffle_topology()
index -= 1
if time.time() - now > timeout:
return False
if self.verbosity >= 1:
self.print_netlist()
return True
def cost(self):
return sum(len(path) for net in self.netlist for path in net.paths)
def cost(self):
return sum(len(path) for net in self.netlist for path in net.paths)
def shuffle_netlist(self):
for net in self.netlist:
net.remove()
net.shuffle_topology()
shuffle(self.netlist)
def shuffle_netlist(self):
for net in self.netlist:
net.remove()
net.shuffle_topology()
shuffle(self.netlist)
def remove_netlist(self):
for net in self.netlist:
net.remove()
def remove_netlist(self):
for net in self.netlist:
net.remove()
def print_netlist(self):
for net in self.netlist:
net.print_net()
print([])
sys.stdout.flush()
def print_netlist(self):
for net in self.netlist:
net.print_net()
print([])
sys.stdout.flush()
def print_pcb(self):
scale = 1.0 / self.resolution
print([self.width * scale, self.height * scale, self.depth])
sys.stdout.flush()
def print_pcb(self):
scale = 1.0 / self.resolution
print([self.width * scale, self.height * scale, self.depth])
sys.stdout.flush()
def print_stats(self):
num_vias = 0
num_terminals = 0
num_nets = len(self.netlist)
for net in self.netlist:
num_terminals += len(net.terminals)
for path in net.paths:
for a, b in zip(path, islice(path, 1, None)):
if a[2] != b[2]:
num_vias += 1
print >> sys.stderr, "Number of Terminals:", num_terminals
print >> sys.stderr, "Number of Nets:", num_nets
print >> sys.stderr, "Number of Vias:", num_vias
def print_stats(self):
num_vias = 0
num_terminals = 0
num_nets = len(self.netlist)
for net in self.netlist:
num_terminals += len(net.terminals)
for path in net.paths:
for a, b in zip(path, islice(path, 1, None)):
if a[2] != b[2]:
num_vias += 1
print >> sys.stderr, "Number of Terminals:", num_terminals
print >> sys.stderr, "Number of Nets:", num_nets
print >> sys.stderr, "Number of Vias:", num_vias
class Net():
def __init__(self, terminals, radius, via, gap, pcb):
self.pcb = pcb
self.terminals = [(r * pcb.resolution, g * pcb.resolution, \
(x * pcb.resolution, y * pcb.resolution, z), \
[(cx * pcb.resolution, cy * pcb.resolution) for cx, cy in s]) \
for r, g, (x, y, z), s in terminals]
self.radius = radius * pcb.resolution
self.via = via * pcb.resolution
self.gap = gap * pcb.resolution
self.paths = []
self.remove()
for term in self.terminals:
for z in range(pcb.depth):
pcb.deform[(int(term[2][0] + 0.5), int(term[2][1] + 0.5), z)] = (term[2][0], term[2][1], float(z))
def __init__(self, terminals, radius, via, gap, pcb):
self.pcb = pcb
self.terminals = [(r * pcb.resolution, g * pcb.resolution, \
(x * pcb.resolution, y * pcb.resolution, z), \
[(cx * pcb.resolution, cy * pcb.resolution) for cx, cy in s]) \
for r, g, (x, y, z), s in terminals]
self.radius = radius * pcb.resolution
self.via = via * pcb.resolution
self.gap = gap * pcb.resolution
self.paths = []
self.remove()
for term in self.terminals:
for z in range(pcb.depth):
pcb.deform[(int(term[2][0] + 0.5), int(term[2][1] + 0.5), z)] = (term[2][0], term[2][1], float(z))
def optimise_paths(self, paths):
opt_paths = []
for path in paths:
opt_path = []
d = (0, 0, 0)
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
d1 = norm_3d(sub_3d(p1, p0))
if d1 != d:
opt_path.append(a)
d = d1
opt_path.append(path[-1])
opt_paths.append(opt_path)
return opt_paths
def optimise_paths(self, paths):
opt_paths = []
for path in paths:
opt_path = []
d = (0, 0, 0)
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
d1 = norm_3d(sub_3d(p1, p0))
if d1 != d:
opt_path.append(a)
d = d1
opt_path.append(path[-1])
opt_paths.append(opt_path)
return opt_paths
def shuffle_topology(self):
shuffle(self.terminals)
def shuffle_topology(self):
shuffle(self.terminals)
def add_paths_collision_lines(self):
for path in self.paths:
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
if a[2] != b[2]:
self.pcb.layers.add_line(p0, p1, self.via, self.gap)
else:
self.pcb.layers.add_line(p0, p1, self.radius, self.gap)
def add_paths_collision_lines(self):
for path in self.paths:
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
if a[2] != b[2]:
self.pcb.layers.add_line(p0, p1, self.via, self.gap)
else:
self.pcb.layers.add_line(p0, p1, self.radius, self.gap)
def sub_paths_collision_lines(self):
for path in self.paths:
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
if a[2] != b[2]:
self.pcb.layers.sub_line(p0, p1, self.via, self.gap)
else:
self.pcb.layers.sub_line(p0, p1, self.radius, self.gap)
def sub_paths_collision_lines(self):
for path in self.paths:
for a, b in zip(path, islice(path, 1, None)):
p0 = self.pcb.grid_to_space_point(a)
p1 = self.pcb.grid_to_space_point(b)
if a[2] != b[2]:
self.pcb.layers.sub_line(p0, p1, self.via, self.gap)
else:
self.pcb.layers.sub_line(p0, p1, self.radius, self.gap)
def add_terminal_collision_lines(self):
for node in self.terminals:
r, g, (x, y, _), s = node
if not s:
self.pcb.layers.add_line((x, y, 0), (x, y, self.pcb.depth - 1), r, g)
else:
for z in range(self.pcb.depth):
for a, b in zip(s, islice(s, 1, None)):
self.pcb.layers.add_line((x + a[0], y + a[1], z), (x + b[0], y + b[1], z), r, g)
def add_terminal_collision_lines(self):
for node in self.terminals:
r, g, (x, y, _), s = node
if not s:
self.pcb.layers.add_line((x, y, 0), (x, y, self.pcb.depth - 1), r, g)
else:
for z in range(self.pcb.depth):
for a, b in zip(s, islice(s, 1, None)):
self.pcb.layers.add_line((x + a[0], y + a[1], z), (x + b[0], y + b[1], z), r, g)
def sub_terminal_collision_lines(self):
for node in self.terminals:
r, g, (x, y, _), s = node
if not s:
self.pcb.layers.sub_line((x, y, 0), (x, y, self.pcb.depth - 1), r, g)
else:
for z in range(self.pcb.depth):
for a, b in zip(s, islice(s, 1, None)):
self.pcb.layers.sub_line((x + a[0], y + a[1], z), (x + b[0], y + b[1], z), r, g)
def sub_terminal_collision_lines(self):
for node in self.terminals:
r, g, (x, y, _), s = node
if not s:
self.pcb.layers.sub_line((x, y, 0), (x, y, self.pcb.depth - 1), r, g)
else:
for z in range(self.pcb.depth):
for a, b in zip(s, islice(s, 1, None)):
self.pcb.layers.sub_line((x + a[0], y + a[1], z), (x + b[0], y + b[1], z), r, g)
def remove(self):
self.sub_paths_collision_lines()
self.sub_terminal_collision_lines()
self.paths = []
self.add_terminal_collision_lines()
def remove(self):
self.sub_paths_collision_lines()
self.sub_terminal_collision_lines()
self.paths = []
self.add_terminal_collision_lines()
def route(self, minz):
try:
self.paths = []
self.sub_terminal_collision_lines()
visited = set()
for index in range(1, len(self.terminals)):
visited |= set([(int(self.terminals[index - 1][2][0]+0.5), int(self.terminals[index - 1][2][1]+0.5), z) for z in range(self.pcb.depth)])
ends = [(int(self.terminals[index][2][0]+0.5), int(self.terminals[index][2][1]+0.5), z) for z in range(self.pcb.depth)]
self.pcb.mark_distances(self.pcb.routing_flood_vectors, self.radius, self.via, self.gap, visited, ends)
ends = [(self.pcb.get_node(node), node) for node in ends]
ends.sort()
_, end = ends[0]
path = [end]
while path[-1] not in visited:
nearer_nodes = self.pcb.all_not_shorting(self.pcb.all_nearer_sorted, \
(self.pcb.routing_path_vectors, path[-1], end, self.pcb.dfunc), path[-1], self.radius, self.via, self.gap)
next_node = next(nearer_nodes)
if minz:
for node in nearer_nodes:
if node[2] == path[-1][2]:
next_node = node
break
path.append(next_node)
visited |= set(path)
self.paths.append(path)
self.pcb.unmark_distances()
self.paths = self.optimise_paths(self.paths)
self.add_paths_collision_lines()
self.add_terminal_collision_lines()
return True
except StopIteration:
self.pcb.unmark_distances()
self.remove()
return False
def route(self, minz):
try:
self.paths = []
self.sub_terminal_collision_lines()
visited = set()
for index in range(1, len(self.terminals)):
visited |= set([(int(self.terminals[index - 1][2][0]+0.5), int(self.terminals[index - 1][2][1]+0.5), z) for z in range(self.pcb.depth)])
ends = [(int(self.terminals[index][2][0]+0.5), int(self.terminals[index][2][1]+0.5), z) for z in range(self.pcb.depth)]
self.pcb.mark_distances(self.pcb.routing_flood_vectors, self.radius, self.via, self.gap, visited, ends)
ends = [(self.pcb.get_node(node), node) for node in ends]
ends.sort()
_, end = ends[0]
path = [end]
while path[-1] not in visited:
nearer_nodes = self.pcb.all_not_shorting(self.pcb.all_nearer_sorted, \
(self.pcb.routing_path_vectors, path[-1], end, self.pcb.dfunc), path[-1], self.radius, self.via, self.gap)
next_node = next(nearer_nodes)
if minz:
for node in nearer_nodes:
if node[2] == path[-1][2]:
next_node = node
break
path.append(next_node)
visited |= set(path)
self.paths.append(path)
self.pcb.unmark_distances()
self.paths = self.optimise_paths(self.paths)
self.add_paths_collision_lines()
self.add_terminal_collision_lines()
return True
except StopIteration:
self.pcb.unmark_distances()
self.remove()
return False
def print_net(self):
scale = 1.0 / self.pcb.resolution
spaths = []
for path in self.paths:
spath = []
for node in path:
spath += [self.pcb.grid_to_space_point(node)]
spaths += [spath]
print([self.radius * scale, self.via * scale, self.gap * scale, \
[(r * scale, g * scale, (x * scale, y * scale, z), \
[(cx * scale, cy * scale) for cx, cy in s]) for r, g, (x, y, z), s in self.terminals], \
[[(x * scale, y * scale, z) for x, y, z in spath] for spath in spaths]])
def print_net(self):
scale = 1.0 / self.pcb.resolution
spaths = []
for path in self.paths:
spath = []
for node in path:
spath += [self.pcb.grid_to_space_point(node)]
spaths += [spath]
print([self.radius * scale, self.via * scale, self.gap * scale, \
[(r * scale, g * scale, (x * scale, y * scale, z), \
[(cx * scale, cy * scale) for cx, cy in s]) for r, g, (x, y, z), s in self.terminals], \
[[(x * scale, y * scale, z) for x, y, z in spath] for spath in spaths]])

372
view.py
View File

@ -16,210 +16,210 @@ photo = None
image = None
def split_paths(paths):
new_paths = []
for path in paths:
new_path = []
for a, b in zip(path, islice(path, 1, None)):
_, _, za = a
_, _, zb = b
if za != zb:
if new_path:
new_path.append(a)
new_paths.append(new_path)
new_paths.append([a, b])
new_path = []
else:
new_path.append(a)
if new_path:
new_path.append(path[-1])
new_paths.append(new_path)
return new_paths
new_paths = []
for path in paths:
new_path = []
for a, b in zip(path, islice(path, 1, None)):
_, _, za = a
_, _, zb = b
if za != zb:
if new_path:
new_path.append(a)
new_paths.append(new_path)
new_paths.append([a, b])
new_path = []
else:
new_path.append(a)
if new_path:
new_path.append(path[-1])
new_paths.append(new_path)
return new_paths
def scale_and_split_tracks(tracks, scale):
for track in tracks:
track[0] *= scale
track[1] *= scale
track[2] *= scale
track[4] = split_paths(track[4])
for i in range(len(track[3])):
r, g, (x, y, z), s = track[3][i]
track[3][i] = r * scale, g * scale, ((x + MARGIN) * scale, (y + MARGIN) * scale, z), [(cx * scale, cy * scale) for cx, cy in s]
for path in track[4]:
for i in range(len(path)):
x, y, z = path[i]
path[i] = (x + MARGIN) * scale, (y + MARGIN) * scale, z
for track in tracks:
track[0] *= scale
track[1] *= scale
track[2] *= scale
track[4] = split_paths(track[4])
for i in range(len(track[3])):
r, g, (x, y, z), s = track[3][i]
track[3][i] = r * scale, g * scale, ((x + MARGIN) * scale, (y + MARGIN) * scale, z), [(cx * scale, cy * scale) for cx, cy in s]
for path in track[4]:
for i in range(len(path)):
x, y, z = path[i]
path[i] = (x + MARGIN) * scale, (y + MARGIN) * scale, z
def get_tracks():
tracks = []
while True:
line = args.infile.readline()
if not line:
tracks = []
break
track = literal_eval(line.strip())
if not track:
break
tracks.append(track)
return tracks
tracks = []
while True:
line = args.infile.readline()
if not line:
tracks = []
break
track = literal_eval(line.strip())
if not track:
break
tracks.append(track)
return tracks
def doframe(dimensions, root, canvas, poll):
global photo, image
global photo, image
tracks = get_tracks()
if poll:
while poll.poll(1):
new_tracks = get_tracks()
if not new_tracks:
break
tracks = new_tracks
if not tracks:
return
tracks = get_tracks()
if poll:
while poll.poll(1):
new_tracks = get_tracks()
if not new_tracks:
break
tracks = new_tracks
if not tracks:
return
pcb_width, pcb_height, pcb_depth = dimensions
scale = args.s[0]
scale_and_split_tracks(tracks, scale)
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
img_width = int(pcb_width * scale)
if args.o[0] == 0:
img_height = int(pcb_height * scale)
else:
img_height = int(pcb_height * pcb_depth * scale)
pcb_width, pcb_height, pcb_depth = dimensions
scale = args.s[0]
scale_and_split_tracks(tracks, scale)
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
img_width = int(pcb_width * scale)
if args.o[0] == 0:
img_height = int(pcb_height * scale)
else:
img_height = int(pcb_height * pcb_depth * scale)
canvas.delete("all")
image = Image.new("RGB", (img_width, img_height), "black")
ctx = aggdraw.Draw(image)
black_brush = aggdraw.Brush('black', opacity = 255)
white_brush = aggdraw.Brush('white', opacity = 255)
red_brush = aggdraw.Brush('red', opacity = 255)
canvas.delete("all")
image = Image.new("RGB", (img_width, img_height), "black")
ctx = aggdraw.Draw(image)
black_brush = aggdraw.Brush('black', opacity = 255)
white_brush = aggdraw.Brush('white', opacity = 255)
red_brush = aggdraw.Brush('red', opacity = 255)
if args.o[0] == 0:
colors = ['red', 'green', 'blue', 'yellow', 'fuchsia', 'aqua']
for depth in range(pcb_depth - 1, -1, -1):
brush = aggdraw.Brush(colors[depth % len(colors)], opacity = 128)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y) for x, y, _ in path], radius, 3, 2)))
ctx.polygon(points, brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
ctx.ellipse((x - via, y - via, x + via, y + via), white_brush)
for r, g, (x, y, _), s in terminals:
if not s:
ctx.ellipse((x - r, y - r, x + r, y + r), white_brush)
else:
if r != 0:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)))
ctx.polygon(points, white_brush)
else:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, white_brush)
else:
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius + gap, 3, 2)))
ctx.polygon(points, white_brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
ctx.ellipse((x - via - gap, y - via - gap, x + via + gap, y + via + gap), white_brush)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
ctx.ellipse((x - r - g, y - r - g, x + r + g, y + r + g), white_brush)
else:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r + g, 3, 2)))
ctx.polygon(points, white_brush)
if r == 0:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, white_brush)
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius, 3, 2)))
ctx.polygon(points, black_brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
ctx.ellipse((x - via, y - via, x + via, y + via), black_brush)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
ctx.ellipse((x - r, y - r, x + r, y + r), black_brush)
else:
if r != 0:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)))
ctx.polygon(points, black_brush)
else:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, black_brush)
ctx.flush()
photo = ImageTk.PhotoImage(image)
canvas.create_image(0, 0, image = photo, anchor = tkinter.NW)
root.update()
root.after(0, doframe, dimensions, root, canvas, poll)
if args.o[0] == 0:
colors = ['red', 'green', 'blue', 'yellow', 'fuchsia', 'aqua']
for depth in range(pcb_depth - 1, -1, -1):
brush = aggdraw.Brush(colors[depth % len(colors)], opacity = 128)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y) for x, y, _ in path], radius, 3, 2)))
ctx.polygon(points, brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
ctx.ellipse((x - via, y - via, x + via, y + via), white_brush)
for r, g, (x, y, _), s in terminals:
if not s:
ctx.ellipse((x - r, y - r, x + r, y + r), white_brush)
else:
if r != 0:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)))
ctx.polygon(points, white_brush)
else:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, white_brush)
else:
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius + gap, 3, 2)))
ctx.polygon(points, white_brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
ctx.ellipse((x - via - gap, y - via - gap, x + via + gap, y + via + gap), white_brush)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
ctx.ellipse((x - r - g, y - r - g, x + r + g, y + r + g), white_brush)
else:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r + g, 3, 2)))
ctx.polygon(points, white_brush)
if r == 0:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, white_brush)
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = list(chain.from_iterable(thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius, 3, 2)))
ctx.polygon(points, black_brush)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
ctx.ellipse((x - via, y - via, x + via, y + via), black_brush)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
ctx.ellipse((x - r, y - r, x + r, y + r), black_brush)
else:
if r != 0:
points = list(chain.from_iterable(thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)))
ctx.polygon(points, black_brush)
else:
points = list(chain.from_iterable([(cx + x, cy + y) for cx, cy in s]))
ctx.polygon(points, black_brush)
ctx.flush()
photo = ImageTk.PhotoImage(image)
canvas.create_image(0, 0, image = photo, anchor = tkinter.NW)
root.update()
root.after(0, doframe, dimensions, root, canvas, poll)
def about_menu_handler():
pass
pass
def main():
global args, image
global args, image
parser = argparse.ArgumentParser(description = 'Pcb layout viewer.')
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--s', nargs = 1, type = int, default = [9], help = 'scale factor, default 9')
parser.add_argument('--f', nargs = 1, type = float, default = [100.0], help = 'framerate, default 100.0')
parser.add_argument('--i', nargs = 1, default = ['pcb.png'], help = 'filename, default pcb.png')
parser.add_argument('--o', nargs = 1, type = int, default = [0], choices=range(0, 2), help = 'overlay modes 0..1, default 0')
args = parser.parse_args()
parser = argparse.ArgumentParser(description = 'Pcb layout viewer.')
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--s', nargs = 1, type = int, default = [9], help = 'scale factor, default 9')
parser.add_argument('--f', nargs = 1, type = float, default = [100.0], help = 'framerate, default 100.0')
parser.add_argument('--i', nargs = 1, default = ['pcb.png'], help = 'filename, default pcb.png')
parser.add_argument('--o', nargs = 1, type = int, default = [0], choices=range(0, 2), help = 'overlay modes 0..1, default 0')
args = parser.parse_args()
poll = 0
if os.name != 'nt':
if args.infile == sys.stdin:
poll = select.poll()
poll.register(args.infile, select.POLLIN)
poll = 0
if os.name != 'nt':
if args.infile == sys.stdin:
poll = select.poll()
poll.register(args.infile, select.POLLIN)
dimensions = literal_eval(args.infile.readline().strip())
pcb_width, pcb_height, pcb_depth = dimensions
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
scale = args.s[0]
pcb_width = int(pcb_width * scale)
if args.o[0] == 0:
pcb_height = int(pcb_height * scale)
else:
pcb_height = int(pcb_height * pcb_depth * scale)
dimensions = literal_eval(args.infile.readline().strip())
pcb_width, pcb_height, pcb_depth = dimensions
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
scale = args.s[0]
pcb_width = int(pcb_width * scale)
if args.o[0] == 0:
pcb_height = int(pcb_height * scale)
else:
pcb_height = int(pcb_height * pcb_depth * scale)
root = tkinter.Tk()
root.maxsize(pcb_width, pcb_height)
root.minsize(pcb_width, pcb_height)
root.title("PCB Veiwer")
menu_bar = tkinter.Menu(root)
sub_menu = tkinter.Menu(menu_bar)
menu_bar.add_cascade(label = 'Help', menu = sub_menu)
sub_menu.add_command(label = 'About', command = about_menu_handler)
root['menu'] = menu_bar
canvas = tkinter.Canvas(root, width = pcb_width, height = pcb_height)
canvas['background'] = 'black'
canvas.pack()
root = tkinter.Tk()
root.maxsize(pcb_width, pcb_height)
root.minsize(pcb_width, pcb_height)
root.title("PCB Veiwer")
menu_bar = tkinter.Menu(root)
sub_menu = tkinter.Menu(menu_bar)
menu_bar.add_cascade(label = 'Help', menu = sub_menu)
sub_menu.add_command(label = 'About', command = about_menu_handler)
root['menu'] = menu_bar
canvas = tkinter.Canvas(root, width = pcb_width, height = pcb_height)
canvas['background'] = 'black'
canvas.pack()
root.after(0, doframe, dimensions, root, canvas, poll)
root.mainloop()
image.save(args.i[0])
root.after(0, doframe, dimensions, root, canvas, poll)
root.mainloop()
image.save(args.i[0])
if __name__ == '__main__':
main()
main()

View File

@ -19,203 +19,203 @@ MARGIN = 2
args = None
def split_paths(paths):
new_paths = []
for path in paths:
new_path = []
for a, b in zip(path, islice(path, 1, None)):
_, _, za = a
_, _, zb = b
if za != zb:
if new_path:
new_path.append(a)
new_paths.append(new_path)
new_paths.append([a, b])
new_path = []
else:
new_path.append(a)
if new_path:
new_path.append(path[-1])
new_paths.append(new_path)
return new_paths
new_paths = []
for path in paths:
new_path = []
for a, b in zip(path, islice(path, 1, None)):
_, _, za = a
_, _, zb = b
if za != zb:
if new_path:
new_path.append(a)
new_paths.append(new_path)
new_paths.append([a, b])
new_path = []
else:
new_path.append(a)
if new_path:
new_path.append(path[-1])
new_paths.append(new_path)
return new_paths
def scale_and_split_tracks(tracks, scale):
for track in tracks:
track[0] *= scale
track[1] *= scale
track[2] *= scale
track[4] = split_paths(track[4])
for i in range(len(track[3])):
r, g, (x, y, z), s = track[3][i]
track[3][i] = r * scale, g * scale, ((x + MARGIN) * scale, (y + MARGIN) * scale, z), [(cx * scale, cy * scale) for cx, cy in s]
for path in track[4]:
for i in range(len(path)):
x, y, z = path[i]
path[i] = (x + MARGIN) * scale, (y + MARGIN) * scale, z
for track in tracks:
track[0] *= scale
track[1] *= scale
track[2] *= scale
track[4] = split_paths(track[4])
for i in range(len(track[3])):
r, g, (x, y, z), s = track[3][i]
track[3][i] = r * scale, g * scale, ((x + MARGIN) * scale, (y + MARGIN) * scale, z), [(cx * scale, cy * scale) for cx, cy in s]
for path in track[4]:
for i in range(len(path)):
x, y, z = path[i]
path[i] = (x + MARGIN) * scale, (y + MARGIN) * scale, z
def get_tracks():
tracks = []
while True:
line = args.infile.readline()
if not line:
tracks = []
break
track = literal_eval(line.strip())
if not track:
break
tracks.append(track)
return tracks
tracks = []
while True:
line = args.infile.readline()
if not line:
tracks = []
break
track = literal_eval(line.strip())
if not track:
break
tracks.append(track)
return tracks
def doframe(frame_num, dimensions, poll, fig, ax):
tracks = get_tracks()
if poll:
while poll.poll(1):
new_tracks = get_tracks()
if not new_tracks:
break
tracks = new_tracks
if not tracks:
return
tracks = get_tracks()
if poll:
while poll.poll(1):
new_tracks = get_tracks()
if not new_tracks:
break
tracks = new_tracks
if not tracks:
return
pcb_width, pcb_height, pcb_depth = dimensions
scale = args.s[0]
scale_and_split_tracks(tracks, scale)
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
img_width = int(pcb_width * scale)
if args.o[0] == 0:
img_height = int(pcb_height * scale)
else:
img_height = int(pcb_height * pcb_depth * scale)
pcb_width, pcb_height, pcb_depth = dimensions
scale = args.s[0]
scale_and_split_tracks(tracks, scale)
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
img_width = int(pcb_width * scale)
if args.o[0] == 0:
img_height = int(pcb_height * scale)
else:
img_height = int(pcb_height * pcb_depth * scale)
ax.clear()
pylab.subplots_adjust(left = 0.0, right = 1.0, bottom = 0.0, top = 1.0)
ax.set_xlim([0, img_width])
ax.set_ylim([0, img_height][::-1])
ax.set(aspect = 1)
ax.axis('off')
ax.clear()
pylab.subplots_adjust(left = 0.0, right = 1.0, bottom = 0.0, top = 1.0)
ax.set_xlim([0, img_width])
ax.set_ylim([0, img_height][::-1])
ax.set(aspect = 1)
ax.axis('off')
if args.o[0] == 0:
colors = ['red', 'green', 'blue', 'yellow', 'fuchsia', 'aqua']
for depth in range(pcb_depth - 1, -1, -1):
brush = colors[depth % len(colors)]
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y) for x, y, _ in path], radius, 3, 2)
poly = plt.Polygon(points, facecolor = brush, edgecolor = 'none', alpha = 0.5)
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
circ = plt.Circle((x, y), radius = via, color = 'white')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
if not s:
circ = plt.Circle((x, y), radius = r, color = 'white')
ax.add_patch(circ)
else:
if r !=0:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
else:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
else:
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius + gap, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
circ = plt.Circle((x, y), radius = via + gap, color = 'white')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
circ = plt.Circle((x, y), radius = r + g, color = 'white')
ax.add_patch(circ)
else:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r + g, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
if r ==0:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius, 3, 2)
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
circ = plt.Circle((x, y), radius = via, color = 'black')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
circ = plt.Circle((x, y), radius = r, color = 'black')
ax.add_patch(circ)
else:
if r !=0:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
else:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
return []
if args.o[0] == 0:
colors = ['red', 'green', 'blue', 'yellow', 'fuchsia', 'aqua']
for depth in range(pcb_depth - 1, -1, -1):
brush = colors[depth % len(colors)]
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y) for x, y, _ in path], radius, 3, 2)
poly = plt.Polygon(points, facecolor = brush, edgecolor = 'none', alpha = 0.5)
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
circ = plt.Circle((x, y), radius = via, color = 'white')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
if not s:
circ = plt.Circle((x, y), radius = r, color = 'white')
ax.add_patch(circ)
else:
if r !=0:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
else:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
else:
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius + gap, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
circ = plt.Circle((x, y), radius = via + gap, color = 'white')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
circ = plt.Circle((x, y), radius = r + g, color = 'white')
ax.add_patch(circ)
else:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r + g, 3, 2)
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
if r ==0:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'white', edgecolor = 'none')
ax.add_patch(poly)
for depth in range(pcb_depth):
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] == path[-1][2] == depth:
points = thicken_path_2d([(x, y + depth * pcb_height * scale) for x, y, _ in path], radius, 3, 2)
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
for track in tracks:
radius, via, gap, terminals, paths = track
for path in paths:
if path[0][2] != path[-1][2]:
x, y, _ = path[0]
y += depth * pcb_height * scale
circ = plt.Circle((x, y), radius = via, color = 'black')
ax.add_patch(circ)
for r, g, (x, y, _), s in terminals:
y += depth * pcb_height * scale
if not s:
circ = plt.Circle((x, y), radius = r, color = 'black')
ax.add_patch(circ)
else:
if r !=0:
points = thicken_path_2d([(cx + x, cy + y) for cx, cy in s], r, 3, 2)
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
else:
points = [(cx + x, cy + y) for cx, cy in s]
poly = plt.Polygon(points, facecolor = 'black', edgecolor = 'none')
ax.add_patch(poly)
return []
def main():
global args
global args
parser = argparse.ArgumentParser(description = 'Pcb layout viewer.')
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--s', nargs = 1, type = int, default = [9], help = 'scale factor, default 9')
parser.add_argument('--f', nargs = 1, type = float, default = [100.0], help = 'framerate, default 100.0')
parser.add_argument('--i', nargs = 1, default = ['pcb.png'], help = 'filename, default pcb.png')
parser.add_argument('--o', nargs = 1, type = int, default = [0], choices=range(0, 2), help = 'overlay modes 0..1, default 0')
args = parser.parse_args()
parser = argparse.ArgumentParser(description = 'Pcb layout viewer.')
parser.add_argument('infile', nargs = '?', type = argparse.FileType('r'), default = sys.stdin, help = 'filename, default stdin')
parser.add_argument('--s', nargs = 1, type = int, default = [9], help = 'scale factor, default 9')
parser.add_argument('--f', nargs = 1, type = float, default = [100.0], help = 'framerate, default 100.0')
parser.add_argument('--i', nargs = 1, default = ['pcb.png'], help = 'filename, default pcb.png')
parser.add_argument('--o', nargs = 1, type = int, default = [0], choices=range(0, 2), help = 'overlay modes 0..1, default 0')
args = parser.parse_args()
poll = None
if os.name != 'nt':
if args.infile == sys.stdin:
poll = select.poll()
poll.register(args.infile, select.POLLIN)
poll = None
if os.name != 'nt':
if args.infile == sys.stdin:
poll = select.poll()
poll.register(args.infile, select.POLLIN)
dimensions = literal_eval(args.infile.readline().strip())
pcb_width, pcb_height, pcb_depth = dimensions
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
scale = args.s[0]
pcb_width = int(pcb_width * scale)
if args.o[0] == 0:
pcb_height = int(pcb_height * scale)
else:
pcb_height = int(pcb_height * pcb_depth * scale)
dimensions = literal_eval(args.infile.readline().strip())
pcb_width, pcb_height, pcb_depth = dimensions
pcb_width += MARGIN * 2; pcb_height += MARGIN * 2
scale = args.s[0]
pcb_width = int(pcb_width * scale)
if args.o[0] == 0:
pcb_height = int(pcb_height * scale)
else:
pcb_height = int(pcb_height * pcb_depth * scale)
fig, ax = plt.subplots(frameon = True, facecolor = 'black')
ani = animation.FuncAnimation(fig, doframe, fargs = (dimensions, poll, fig, ax), interval = 10, blit = False, repeat = True)
plt.show()
fig, ax = plt.subplots(frameon = True, facecolor = 'black')
ani = animation.FuncAnimation(fig, doframe, fargs = (dimensions, poll, fig, ax), interval = 10, blit = False, repeat = True)
plt.show()
if __name__ == '__main__':
main()
main()