| #!/usr/bin/env python3 |
| # takes a lef file and a rectangle => trims all RECT statements within the area |
| import re |
| import sys |
| |
| ARGV = sys.argv |
| if len(ARGV) < 5: |
| print("Usage " + ARGV[0] + " llx lly urx ury") |
| sys.exit(-1) |
| LLX = float(ARGV[1]) |
| LLY = float(ARGV[2]) |
| URX = float(ARGV[3]) |
| URY = float(ARGV[4]) |
| LAYERS = ["li1", "met1", "met2", "met3", "met4", "met5"] |
| RECT_REGEX = r"^\s*RECT\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s+;$" |
| # SIZE_REGEX = r"^\s*SIZE\s+(-?\d+\.?\d*)\s+BY\s+\s+(-?\d+\.?\d*);$" |
| |
| def get_cut_rect_x(rect, axis): |
| """ |
| cuts one rect about an x axis |
| """ |
| rects = [rect] |
| llx, lly, urx, ury = rect |
| if llx < axis and urx > axis: |
| rects = [(llx, lly, axis, ury), |
| (axis, lly, urx, ury)] |
| return rects |
| |
| def get_cut_rect_y(rect, axis): |
| """ |
| cuts one rect about an y axis |
| """ |
| rects = [rect] |
| llx, lly, urx, ury = rect |
| if lly < axis and ury > axis: |
| rects = [(llx, lly, urx, axis), |
| (llx, axis, urx, ury)] |
| return rects |
| |
| def rects2cutrects(rects, axis, direction): |
| """ |
| cut a list of rects (4-tuple) and returns another list of of rects (4-tuple) |
| cut by an x or y axis |
| |
| axix is a position |
| |
| direction is either 'x' or 'y' |
| """ |
| rects_cut = [] |
| if direction == 'x': |
| for rect in rects: |
| rects_cut += get_cut_rect_x(rect, axis) |
| else: |
| for rect in rects: |
| rects_cut += get_cut_rect_y(rect, axis) |
| return rects_cut |
| |
| def get_all_cut_rects(rect): |
| """ |
| cut a rect about the 4 axis LLX, LLY, URX, URY |
| """ |
| rects = [rect] |
| rects = rects2cutrects(rects, LLX, 'x') |
| rects = rects2cutrects(rects, URX, 'x') |
| rects = rects2cutrects(rects, LLY, 'y') |
| rects = rects2cutrects(rects, URY, 'y') |
| return rects |
| |
| def rectify(rects): |
| """ |
| gets a list of already cut rects (4-tuple) and returns another list of of |
| rects (4-tuple) that are not within LLX, LLY, URX, URY |
| """ |
| rect_outside = [] |
| for rect in rects: |
| llx, lly, urx, ury = rect |
| if llx < LLX or llx > URX or urx > URX or urx < LLX \ |
| or lly < LLY or lly > URY or ury > URY or ury < LLY: |
| rect_outside += [rect] |
| return rect_outside |
| |
| def print_rects(prefix, rects): |
| for rect in rects: |
| llx, lly, urx, ury = rect |
| print( prefix + "RECT %f %f %f %f ;" % (llx, lly, urx, ury)) |
| |
| layer = "" |
| for line in sys.stdin: |
| if line.isspace(): |
| continue |
| rect_match = re.search(RECT_REGEX, line) |
| if rect_match: |
| llx, lly, urx, ury = float(rect_match.group(1)), float(rect_match.group(2)), float(rect_match.group(3)), float(rect_match.group(4)) |
| if (lly < LLY and ury < LLY) or (lly > URY and ury > URY) \ |
| or (llx < LLX and urx < LLX) or (llx > URX and urx > URX): # outside the whole thing |
| rects = [(llx, lly, urx, ury)] |
| else: |
| rects = rectify(get_all_cut_rects((llx, lly, urx, ury))) |
| if len(rects) > 0: |
| print(layer) |
| if layer != "": # LAYER printed, clear it |
| layer = "" |
| print_rects(line[:line.find('R')], rects) |
| else: |
| if line.find("LAYER") != -1: # print it only if there're RECTs |
| layer = line |
| else: |
| print(line, end='') |