diff --git a/layer.py b/layer.py index db234d3..a625182 100644 --- a/layer.py +++ b/layer.py @@ -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 diff --git a/mymath.py b/mymath.py index 755f7e6..cf1a863 100644 --- a/mymath.py +++ b/mymath.py @@ -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 diff --git a/pcb.py b/pcb.py index 4fc4c79..507411a 100755 --- a/pcb.py +++ b/pcb.py @@ -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() diff --git a/router.py b/router.py index 75f61a3..aca16b3 100644 --- a/router.py +++ b/router.py @@ -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]]) diff --git a/view.py b/view.py index 97dcd91..12523d9 100755 --- a/view.py +++ b/view.py @@ -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() diff --git a/view_mpl.py b/view_mpl.py index b618125..9cf65c6 100755 --- a/view_mpl.py +++ b/view_mpl.py @@ -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()