pads_in.log‘ does not exist.

在将包含非法字符的 PADS ASCII 文件导入 ALLEGRO 过程中,会遇到 'pads_in.log' 不存在的问题。这些非法字符包括:`$~@#$%^&*()='[]?/<>&!.,;{}
#!/bin/env python # 必须写在第一行 # -*- coding: utf-8 -*- ################################################# # Author: songwenhua # Function:客户阻抗线连续性检查 # Date: 2025-11-05 # v1.00 songwenhua 用户需求号: 2482 任务ID:2100 # LOAD_MODE__ import os import re import sys from py39COM import Gateway, InCAM from py39Tools import TableWidget from ICO import ICO from ICNET import ICNET from XMLParse import XMLParsePlus from messageBox import messageBox from EqHelper import EqHelper from PyQt5.QtWidgets import QWidget, QApplication, QComboBox from collections import defaultdict, deque from functools import partial import math # from img import apprcc_rc from pprint import pprint import time class chk_Conti_zkline: def __init__(self): # self.setWindowFlags(Qt.WindowStaysOnTopHint) self.JOB = os.environ.get('JOB', None) self.STEP = os.environ.get('STEP', None) # self.chklist = os.environ.get('chklist', None) # --启动pycharm.sh时,里面有export INCAM_DEBUG=yes设置此环境变量 INCAM_DEBUG = os.getenv('INCAM_DEBUG', None) # 接口定义 if INCAM_DEBUG == 'yes': # 通过genesis gateway命令连结pid进行会话,不用在genesis环境下运行,直接用gateway的方式,可在pycharm环境下直接debug self.incam = Gateway() # 方法genesis_connect通过查询log-genesis文件获取的料号名 self.JOB = self.incam.job_name self.STEP = self.incam.step_name self.pid = self.incam.pid else: self.incam = InCAM() self.pid = os.getpid() self.ico = ICO(incam=self.incam) self.icNet = ICNET(incam=self.incam) self.jobName = self.ico.SimplifyJobName(jobName=self.JOB) self.dbSite = self.ico.GetDBSite(JOB=self.JOB) self.SITE = self.ico.GetSite(JOB=self.JOB) self.getinfomation_dict = defaultdict(defaultdict) self.ballPadIndexList = defaultdict(list) self.layerMatrix = self.ico.GetLayerMatrix() self.zkLineIndex = defaultdict(defaultdict) self.step_list = self.ico.GetStepList() layer_list = self.ico.GetLayerList() self.zk_siglay = {} self.zkLayerList = self.getZKLayer() # 获取阻抗线层别 self.run() def getZKLayer(self): """ 获取阻抗线层别 :return: 阻抗线层别 """ zkLayerList = list() layerList = self.layerMatrix['allLay'] # self.ico.GetLayerList() for lay in layerList: for t in ('s', 'ss', 'gsg', 'gssg'): pattern_tmp = re.compile(r'^((?:un-)?(\d+|[tb])zk)-(\d+\.?\d*)-(%s)-?(\d+\.?\d*)?-?(\d+\.?\d*)?-?(\d+\.?\d*)?$' % t)#存在un开头的阻抗层 matchObj = re.match(pattern_tmp, lay) if matchObj: matchList = matchObj.groups() zkLayerList.append(lay) self.getinfomation_dict[lay]['layer'] = matchList[0] print(zkLayerList) if len(zkLayerList) > 0: SignalLayer_list = self.layerMatrix['sigAllLay'] for i in range(len(SignalLayer_list)): if i == 0: self.zk_siglay['tzk'] = SignalLayer_list[0] elif i == (len(SignalLayer_list) - 1): self.zk_siglay['bzk'] = SignalLayer_list[-1] else: self.zk_siglay[str(i + 1) + 'zk'] = SignalLayer_list[i] self.zk_siglay['un-' + str(i + 1) + 'zk'] = SignalLayer_list[i]#还要加一个un-开头的对应线路层! print("zk_siglay : %s" % self.zk_siglay) for lay in self.getinfomation_dict.keys(): for key in self.zk_siglay: if self.getinfomation_dict[lay]['layer'] == key: self.getinfomation_dict[lay]['sigLayerNum'] = str(SignalLayer_list.index(self.zk_siglay[key]) + 1) self.getinfomation_dict[lay]['sigLayerName'] = str(self.zk_siglay[key]) break else: messageBox.showMessage(message='没有识别到阻抗线层别,请规范命名(eg:tzk-gssg-100)', bitmap='critical') exit() return zkLayerList def get_unique_endpoints(self, job, step, backup_layer): """ 提取 backup_layer 层上所有 line/arc 的端点, 返回仅出现一次的“末端”点(即非连接点) """ features = self.ico.GetFeaturesPro(job=job, step=step, layer=backup_layer) if not features: print(f"[WARN] No features found on layer '{backup_layer}'") return [] endpoints = [] for feat in features: ftype = feat['type'] if ftype == 'line' or ftype == 'arc': xs, ys = feat['xs'], feat['ys'] xe, ye = feat['xe'], feat['ye'] endpoints.append((round(xs, 3), round(ys, 3))) endpoints.append((round(xe, 3), round(ye, 3))) # elif ftype == 'arc': # x_start, y_start = feat['xs'], feat['ys'] # x_end, y_end = feat['xe'], feat['ye'] # endpoints.append((round(x_start, 6), round(y_start, 6))) # endpoints.append((round(x_end, 6), round(y_end, 6))) # 统计每个点出现次数 point_count = defaultdict(int) for pt in endpoints: point_count[pt] += 1 # 只保留只出现一次的点(真正的末端) unique_ends = [pt for pt, cnt in point_count.items() if cnt == 1] unique_ends.sort(key=lambda p: (p[0], p[1])) # 按坐标排序便于调试 print(f"[INFO] Found {len(unique_ends)} unique endpoints on '{backup_layer}'.") return unique_ends def selectun(self, backup_layer, zkLay): """ 完整流程: 1. 复制非 line/arc 图形到 '01' 层 2. 局部合并为独立 surface 3. 提取 backup_layer 的唯一端点 4. 删除覆盖这些端点的 surface 5. 返回状态信息供 run() 使用 """ zk2SigLay = self.getinfomation_dict[zkLay]['sigLayerName'] zkLineIndex = self.zkLineIndex[zkLay]['index'] step = 'edit' ######初始化环境####### self.ico.ClearAll() self.ico.ResetFilter() self.incam.COM(f'affected_layer, name={backup_layer}, mode=single, affected=yes') self.incam.COM(f'display_layer, name={zk2SigLay}, display=yes') # if self.ico.IsLayerExist('01'): # self.ico.DelLayer('01') #如果已经存在01层就重新创建 #创建01层 # self.incam.COM(f"matrix_insert_layer,job={self.JOB},matrix=matrix,subsystem=1-Up-Edit") # self.incam.COM("display_layer,name=01,hide_others=yes") self.ico.CreateLay(layer_list=['01']) #######处理每根阻抗线,复制并合并 surface 到 '01'层####### for idx, info in enumerate(zkLineIndex): x, y, tmpID = info['x'], info['y'], info['id'] #跨网络选择 self.incam.COM("sel_clear_feat") self.incam.COM("clear_highlight") self.incam.COM(f'sel_board_net_feat, operation=select, x={x}, y={y}, tol=1, use_ffilter=no') #坐标点选 features = self.ico.GetFeatureFullInfo(step=step, layer=zk2SigLay, mode='select') non_line_arcs = [f for f in features if f['type'] not in ('line', 'arc')] if not non_line_arcs: print(f"{backup_layer}层中没有非line非弧图形") continue # 复制到 '01' 层 self.incam.COM( "sel_copy_other, dest=layer_name, target_layer=01, invert=no, " "dx=0, dy=0, size=0, x_anchor=0, y_anchor=0" ) # 切换到 '01' 层进行局部合并 self.ico.DispWork(layer='01') # self.incam.COM("sel_clear_feat") # self.incam.COM(f"sel_all_feat, operation=select, x={x}, y={y}, tol=0.3, use_ffilter=no") self.incam.COM(f"sel_all_feat") self.incam.COM('get_select_count') selected_count = int(self.incam.COMANS) if selected_count > 0: #合并 self.incam.COM( "sel_cont_resize, accuracy=0, break_to_islands=yes, " "island_size=0, hole_size=0, drill_filter=no, corner_ctl=no" ) #######获取备份层中的唯一端点###### print(f"在{backup_layer}层查是否有端点坐标") unique_endpoints = self.get_unique_endpoints(job=self.JOB, step=step, backup_layer=backup_layer) if not unique_endpoints: print(f"在{backup_layer}层没有到端点坐标") # 检查 01 层状态 # features_01 = self.ico.GetFeaturesPro(job=self.JOB, step=step, layer='01') # return { # 'endpoints_count': 0, # 'surfaces_deleted': 0, # 'remaining_on_01': len(features_01) > 0 # } #############删除 '01' 层中覆盖这些端点的 surface############ print(f"[PHASE 3] Checking {len(unique_endpoints)} endpoints against surfaces on '01'...") self.ico.DispWork(layer='01') self.incam.COM("sel_clear_feat") deleted_surface_count = 0 processed_centers = set() for i, (ux, uy) in enumerate(unique_endpoints): print(f" [CHECK] Endpoint {i+1}: ({ux:.4f}, {uy:.4f})") self.incam.COM("sel_clear_feat") self.incam.COM(f"sel_all_feat, operation=select, x={ux}, y={uy}, tol=0.01, use_ffilter=no") #在 '01' 层尝试以极小容差(tol=0.01)选择该点附近图形。检查是否有 surface 类型被选中。 self.incam.COM('get_select_count') selected_features = int(self.incam.COMANS) if not selected_features: continue for feat in selected_features: if feat['type'] == 'surface': center_key = (round(feat['x'], 3), round(feat['y'], 3)) if center_key not in processed_centers: print(f" --> Deleting surface at center ({feat['x']:.3f}, {feat['y']:.3f})") processed_centers.add(center_key) deleted_surface_count += 1 #########执行删除############# if deleted_surface_count > 0: self.incam.COM("sel_clear_feat") self.incam.COM('get_select_count') all_surfs = int(self.incam.COMANS) for surf in all_surfs: if surf['type'] == 'surface': key = (round(surf['x'], 3), round(surf['y'], 3)) if key in processed_centers: self.incam.COM(f"sel_single_feat, operation=select, x={surf['x']}, y={surf['y']}, tol=0.1") self.incam.COM("sel_delete") # === 最终判断 '01' 层是否还有内容 === features_01 = self.ico.GetFeaturesPro(job=self.JOB, step=step, layer='01') has_remaining = len(features_01) > 0 return has_remaining, features_01 # return { # 'endpoints_count': len(unique_endpoints), # 'surfaces_deleted': deleted_surface_count, # 'remaining_on_01': has_remaining # } def selectBallPad(self, zkLay, x, y): """ 判断指定坐标点是否与背面ball pad导通 :param zkLay: 阻抗层名称 :param x: 检查点的x坐标 :param y: 检查点的y坐标 :return: bool 是否导通 """ # 阻抗层对应的线路层 zk2SigLay = self.getinfomation_dict[zkLay]['sigLayerName']#self.getinfomation_dict得到的是原始阻抗层,而不是_bak备份阻抗层 sigBot = self.layerMatrix['sigAllLay'][-1] #线路层最后一层,背面 # 设置工作环境 self.ico.ClearAll() self.ico.ResetFilter() self.incam.COM(f'affected_layer, name={sigBot}, mode=single, affected=yes') self.incam.COM(f'display_layer, name={zk2SigLay}, display=yes') self.incam.COM(f'work_layer, name={zk2SigLay}') # 执行选择 self.incam.COM("sel_clear_feat") #清除之前的选择 self.incam.COM("clear_highlight") self.incam.COM(f'sel_board_net_feat, operation=select, x={x}, y={y}, tol=1, use_ffilter=no') # 获取选中特征 featureFullInfo_sigBot = self.ico.GetFeatureFullInfo(step=self.STEP, layer=sigBot, mode='select') # 检查背面ball pad # 对于背面sig选到的物体,做个筛选,如果是pad且是.smd属性,说明选到了ball pad selectPadList = [info for info in featureFullInfo_sigBot if info['type'] == 'pad' and (info['attr'] == '.smd' or info['attr'] == '.smd,.bga' or info['attr'] == '.smd,.lga' or info['attr'] == '.smd,.smt_pad' or info['attr'] == '.smd,.test_pad')] # 20241209 新增ball pad属性是.smd.bga和.smd.lga return len(selectPadList) > 0 # 如果到ball pad则返回True def cleanup_short_polylines(self, step, backup_layer, min_length=8.0): """ 删除总长度 < min_length 的整根 polyline(由多个 line 与arc 组成) 利用 feature['length'] 避免重复计算几何距离 """ features = self.ico.GetFeatures(step, backup_layer) # 提取所有 line 和 arc valid_features = [f for f in features if f['type'] in ('line', 'arc')] if not valid_features: return # #######构建拓扑图 端点->线段#### graph = defaultdict(list) # 坐标 -> 相邻坐标 coord_to_feats = defaultdict(list) # 坐标 -> (index, feature) for idx, feat in enumerate(valid_features): xs = round(feat['xs'], 3) ys = round(feat['ys'], 3) xe = round(feat['xe'], 3) ye = round(feat['ye'], 3) start = (xs, ys) end = (xe, ye) graph[start].append(end) graph[end].append(start) coord_to_feats[start].append((idx, feat)) coord_to_feats[end].append((idx, feat)) visited_coords = set() short_polyline_seeds = [] # 存储每根短 polyline 的一个起点用于删除 ##########BFS 遍历每个连通组件########### for coord in list(graph.keys()): if coord in visited_coords: continue queue = deque([coord]) current_visited_coords = set() current_feat_indices = set() while queue: curr = queue.popleft() if curr in current_visited_coords: continue current_visited_coords.add(curr) for neighbor in graph[curr]: # 查连接 curr和neighbor 的 feature found = False for feat_idx, feat in coord_to_feats[curr]: if feat_idx in current_feat_indices: continue # 判断是否连接 curr 和 neighbor s = (round(feat['xs'],3), round(feat['ys'],3)) e = (round(feat['xe'],3), round(feat['ye'],3)) connected = (curr == s and neighbor == e) or (curr == e and neighbor == s) if connected: current_feat_indices.add(feat_idx) found = True break if not found: continue # 没有可用边 if neighbor not in current_visited_coords: queue.append(neighbor) # 标记这些点已被全局访问 visited_coords.update(current_visited_coords) if not current_feat_indices: continue ################计算当前 polyline 总长度########### total_length = sum(valid_features[i]['length'] for i in current_feat_indices) if total_length < min_length: # 一个端点作为选择依据(度为1的点) endpoints = [pt for pt in current_visited_coords if len(graph[pt]) == 1] seed = endpoints[0] if endpoints else next(iter(current_visited_coords)) short_polyline_seeds.append(seed) ##########删除:选中所有短 polyline######### if short_polyline_seeds: self.incam.COM("sel_clear_feat") for x, y in short_polyline_seeds: self.incam.COM(f"sel_polyline_feat,operation=select,x={x:.3f},y={y:.3f},tol=1") self.incam.COM("sel_delete") def run(self): """ 处理Y形阻抗线检测与清理的主执行函数 修改重点: - 每个 backup_layer 单独处理:检测 -> 标记 -> 删除 -> 刷新 - 每次删除后重新获取 features,确保状态最新 - 避免 Entity does not exist 错误 """ job = self.JOB step = 'edit' #在edit层 backup_layers = [] self.ico.ClearAll() self.zkLineIndex = defaultdict(lambda: defaultdict(list)) ######## 创建备份层 ################## for zklay in self.zkLayerList: zkLay_bak = f'{zklay}_bak' self.zkLineIndex[zklay]['zkLaybak'] = zkLay_bak self.ico.DelLayer(layer_list=[zkLay_bak]) self.ico.DispWork(zklay) self.incam.COM(f'sel_copy_other,dest=layer_name,target_layer={zkLay_bak},invert=no,dx=0,dy=0,size=0,x_anchor=0,y_anchor=0') backup_layers.append(zkLay_bak) self.ico.ClearLayer() unthrough_lay = [] if self.ico.IsLayerExist('01'): self.ico.DelLayer('01') #如果已经存在01层就删除 print("2222222222222222222222222222222222222222222222") ############# 遍历每个 step ############## for backup_layer in backup_layers: original_layer = backup_layer.replace('_bak', '') # self.ico.DispWork(backup_layer) # #############获取当前特征############ features = self.ico.GetFeaturesPro(job, step, backup_layer) if not features: continue # self.incam.COM("sel_clear_feat") # 清空之前选择 has_remaining, features_01 = self.selectun(backup_layer=backup_layer, zkLay=original_layer) if not has_remaining: continue #############待删除坐标的集合(仅针对当前 layer)############ seeds_to_delete = set() ##############判断原线路层中与01层touch的阻抗线是否与背面的ball pad导通########### for feat in features_01: layer_through = False if feat['type'] not in ('line', 'arc'): continue xs, ys = round(feat['xs'], 3), round(feat['ys'], 3) xe, ye = round(feat['xe'], 3), round(feat['ye'], 3) start_1 = self.selectBallPad(zkLay=original_layer, x=xs, y=ys) end_1 = self.selectBallPad(zkLay=original_layer, x=xe, y=ye) if (start_1 or end_1): layer_through = True break if layer_through: connection_to_ballpad = True # problem_x, problem_y = x, y break # 到第一个即可跳出 else: seeds_to_delete.add((x, y)) #到备份层中与01层touch的阻抗线 if connection_to_ballpad: # 记录 layer 和坐标 unthrough_lay.append({'layer': backup_layer}) ########统一判断并提示################ if unthrough_lay: lines = [] for pt in unthrough_lay: lines.append(f"{pt['layer']}") # ({pt['x']:.3f}, {pt['y']:.3f}) layer_list_str = ";".join(lines) messageBox.showDialog( title='提示', text=f'{layer_list_str}层存在阻抗线不连续,此阻抗线与背面ball pad导通\n\n' '1、人为确认是否为分流设计\n' '2、如为分流设计,需与客户确认是否设计异常,与客户EQ此组对抗通过测量科邦卡控阻值,\n' ' 如客户不同意,内部策划列难点评估测科邦', bitmap='warning', buttons=['OK'], defaultButton='OK' ) self.ico.ClearLayer() #############到孤立不导通线段############ for feat in features: if feat['type'] not in ('line', 'arc'): continue xs, ys = round(feat['xs'], 3), round(feat['ys'], 3) xe, ye = round(feat['xe'], 3), round(feat['ye'], 3) start_ok = self.selectBallPad(zkLay=original_layer, x=xs, y=ys) end_ok = self.selectBallPad(zkLay=original_layer, x=xe, y=ye) if not (start_ok or end_ok): seeds_to_delete.add((xs, ys)) ############执行删除操作 ############ self.incam.COM("sel_clear_feat") # 1. 先清理 <8mm的polyline self.cleanup_short_polylines(job=job, step='edit', backup_layer=backup_layer) # 2. 再删除01层与原线路层以及不导通线对应的 polyline current_features = self.ico.GetFeatures(step, backup_layer) # 刷新!重新获取每个备份层的特征,防止 entity not exist valid_coords = {(round(f['xs'],3), round(f['ys'],3)) for f in current_features if f['type'] in ('line','arc')} valid_coords.update({(round(f['xe'],3), round(f['ye'],3)) for f in current_features if f['type'] in ('line','arc')}) for x, y in seeds_to_delete: if (round(x,3), round(y,3)) not in valid_coords: continue # 已被前面的 cleanup 删除,跳过 try: self.incam.COM(f"sel_polyline_feat,operation=select,x={x:.3f},y={y:.3f},tol=1") except: pass # 忽略异常 self.incam.COM("sel_delete") self.ico.ClearLayer() ############判断是否为空层############ features_after = self.ico.GetFeaturesPro(job, step, backup_layer) has_valid = any(f['type'] in ('line', 'arc') for f in features_after) msg = ( f'{backup_layer}存在Y形阻抗线,同组无可测阻抗线,与客户EQ此组阻抗通过测量科邦卡控阻值,如客户不同意,内部策划列难点评估测科邦' if not has_valid else f'{backup_layer}存在Y形阻抗线,同组存在可测阻抗线,EQ客户Y型阻抗线follow同组可测阻抗线进行调整' ) messageBox.showMessage( title='提示', text=msg, bitmap='warning', buttons=['OK'], defaultButton='OK' ) self.ico.ClearLayer() sys.exit() if __name__ == "__main__": app = QApplication(sys.argv) analyzer = chk_Conti_zkline() 在run函数中我想要实现:备份所有阻抗层,备份为_bak;然后将备份层阻抗线touch到的原线路层中非line非arc图形选中复制到01层,再分别将每根阻抗线touch到的图形在01层中合成surface 接着获取对应阻抗备份层所有线路的端点坐标(只要不重复的坐标点,因为有许多根线相连,不重复的坐标点是整根线真正的端点),并删除在01层中cover端点坐标的sruface物体;然后判断原线路层与01层touch的阻抗线是否与背面的pad导通(selectBallPad函数已经能够实现),导通的话,messagebox提示并结束整个代码; 没有导通的话,第一:就在备份层阻抗线路删除与01层touch的整根线路polyline(注意polyline是一根很长线,由很多短的line组成)self.incam.COM(f"sel_polyline_feat,operation=select,x={feature[‘xs’]},y={feature[‘ys’]}")命令能够通过一个坐标点选中一根polyline 第二:删除整根线长小于8的polyline;第三:删除不与背面ball pad导通的polyline; 第四:判断经过删除的备份层是否为空,是与不是都输出messagebox提示并结束整个代码 如果有必要也可改动selectun函数与get_unique_endpoints函数代码
最新发布
11-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值