import csv import os import sys from copy import deepcopy from glob import glob from kikit.panelize import Origin,getOriginCoord from kikit.common import findBoardBoundingBox from pcbnewTransition.pcbnew import LoadBoard YY1_SEP = ["","","","","","","","","","","","","",""] YY1_HEADER = ["NEODEN","YY1","P&P FILE","","","","","","","","","","",""] YY1_PANEL = ["PanelizedPCB","UnitLength",0,"UnitWidth",0,"Rows",1,"Columns",1,] YY1_NOZZLE_DEF = ["NozzleChange","OFF","BeforeComponent",1,"Head1","Drop","Station1","PickUp","Station1",] YY1_COMP_HEADER = ["Designator","Comment","Footprint","Mid X(mm)","Mid Y(mm) ","Rotation","Head ","FeederNo","Mount Speed(%)","Pick Height(mm)","Place Height(mm)","Mode", "Skip"] YY1_EXTRA_IND = YY1_COMP_HEADER.index("Head ") YY1_FEEDER_IND = YY1_COMP_HEADER.index("FeederNo") - YY1_EXTRA_IND YY1_DEF_EXTRA = [0, 0, 50, 0.0, 0.0, 1, 0] KI_POS_SUFFIX = "_cpl" pcb_dir = sys.argv[1] pcb_file = glob(pcb_dir + "/*.kicad_pcb") board = LoadBoard(pcb_file[0]) sourceArea = findBoardBoundingBox(board) bottomOrig = [(a - b)/10**6 for a,b in zip(*[list(getOriginCoord(o, sourceArea)) for o in [Origin.BottomRight, Origin.BottomLeft]])] print("bottom Orig: ", bottomOrig) output_dir = deepcopy(pcb_dir) csv_files = glob(output_dir + "/*.csv") print("CSV Files: ", csv_files) if len(csv_files) < 1: output_dir = os.path.join(os.environ.get('CI_PROJECT_DIR', ''), '') + "Fabrication/" + output_dir csv_files = glob(output_dir + "/*.csv") input = next(filter(lambda f: KI_POS_SUFFIX in f, csv_files)) output = output_dir + "/" + input.split("/")[-1].split(KI_POS_SUFFIX)[0] + "-neo-pos.csv" try: feed_opt = next(filter(lambda f: "feed" in f, csv_files)) except: feed_opt = None rows_in = [] with open(input, newline='') as csvfile: spamreader = csv.reader(csvfile, delimiter=',', quotechar='|') for row in spamreader: # Round floats to 2 places for n, r in enumerate(row): r = r.strip('"') row[n] = r try: r = round(float(r),2) row[n] = "{:.2f}".format(r) except: continue rows_in.append(row) in_header = rows_in[0] posx = in_header.index("PosX") posy = in_header.index("PosY") desig = in_header.index("Ref") comm = in_header.index("Val") foot = in_header.index("Package") rot = in_header.index("Rot") out_inds = [desig, comm, foot, posx, posy, rot] def pos_diff(pos1, pos2): return sum([(pos1[i] - pos2[i])**2 for i in range(2)])**1/2 # Fiducial fids = [x for x in filter(lambda x: "Fiducial" in x, rows_in)] for f in fids: rows_in.remove(f) # Components comps = rows_in[1:] comp_feed = {} feeder = 1 # Load in optional file if feed_opt is not None: # Read in feeder options for components with open(feed_opt, newline='') as csvfile: spamreader = csv.reader(csvfile, delimiter=',', quotechar='|') for row in spamreader: comp_feed[row[0]] = row[1:] f = int(row[YY1_FEEDER_IND]) if f > feeder: feeder = f def comp_name(row): return row[foot] + row[comm] # Add all component types for comp in comps: name = comp_name(comp) if name not in comp_feed: entry = deepcopy(YY1_DEF_EXTRA) entry[YY1_FEEDER_IND] = feeder comp_feed[name] = entry feeder += 1 def comp_format(filt, offset): filt_rows = filter(filt, rows_in[1:]) out = [] for r in filt_rows: t = [] for i in out_inds: t.append(r[i]) t.extend(comp_feed[comp_name(r)]) # Cannot go below 0, so just use abs to take care of sign for n,p in enumerate([out_inds.index(n) for n in [posx, posy]]): t[p] = "{:.2f}".format(abs(float(t[p]) - offset[n])) rotation = float(t[rot]) rotation = rotation + offset[2] # Wrap the phase [-180, 180] rotation = (rotation + 180.0) % (2 * 180.0) - 180.0 t[rot] = "{:.2f}".format(rotation) out.append(t) return out # Top and bottom origins = {"top": [0.0,0.0], "bottom": list(bottomOrig)} print("origins:", origins) for tag, origin in origins.items(): rotation = 180.0 * (tag != "top") print("rot: ", rotation) # Find fiducial furthest away from origin fid_pos = deepcopy(origin) fid_dist = 0.0 for f in fids: pos = [float(f[posx]), float(f[posy])] d = pos_diff(pos, origin) if d > fid_dist : fid_pos = pos fid_dist = d print("Fid pos: ", fid_pos) # component formatting comp = comp_format(lambda x: tag in x, origin + [rotation]) # Format output rows_out = [YY1_HEADER, YY1_SEP, YY1_PANEL, YY1_SEP] # y is still same dir, but x gets flipped, so the x calc is opposite sign rows_out.append(["Fiducial","1-X", "{:.2f}".format(abs(fid_pos[0] - origin[0])) ,"1-Y","{:.2f}".format(fid_pos[1] - origin[1]) ,"OverallOffsetX",0,"OverallOffsetY",0,]) rows_out.append(YY1_SEP) for _ in range(4): rows_out.append(YY1_NOZZLE_DEF) rows_out.append(YY1_SEP) rows_out.append(YY1_COMP_HEADER) rows_out.extend(comp) # Write output with open(output.split(".csv")[0] + "_" + tag + ".csv", 'w', newline='') as csvfile: spamwriter = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) for row in rows_out: spamwriter.writerow(row)