用Python编写Genesis2000&InCAM&InCAMPro脚本

该文章已生成可运行项目,

用Python编写Genesis2000&InCAM&InCAMPro脚本

  • 以添加板边四个定位孔为例(add_pnl_pad.py)

1.需求分析

  • PCB制造业制前工程作业需要设计一个适合板厂生产的排版设计,我们称为生产排版panel,panel生产会留边用于设计机台所需的各类工具孔及靶标光学点等,这个设计过程如果依赖CAM工程师会非常耗时,所以体现我们价值的时候又来了,如何通过脚本自动化来实现?

2.业务场景

  • CAM工程师在制作panel模块时需要为panel留边位置添加生产时需要用到的工具孔等标识信息,实际的添加添加工作是一个庞大且复杂的系统工程,以现阶段生产力发展阶段手动添加很显然不符合高效高品质的现代化制造要求,所以我们会提前设计板边tooling并形成一份完整的设计规则,最终以自动化的方式来实现

3.实现逻辑

需求及业务场景有了,我们看看具体的实施逻辑

  • 首先,我们需要配置软件的脚本语言环境;
  • 其次,我们需要获取软件的指令参数;
  • 再次,我们需要按操作流程(打开panel->获取panel相关信息->添加工具孔)执行作业;
  • 最后,我们根据具体的业务需求编写代码逻辑

4.软件脚本语言环境配置

5.代码实现

  • 第一步,实现添加一个pad的代码:

    • 首先查看开发文档如何使用调用软件内部指令
      参考博文Genesis2000/InCAM/InCAMPro基础命令,根据文档添加pad的执行及参数如下:

      # C shell代码,保存为文本Genesis2000/InCAM/InCAMPro可直接运行
      COM add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1;
      
    • 然后查看官方提供的开发接口incam.py(Genesis2000与其类似,部分参数有一些差异,极少数指令不被兼容特殊处理即可)找到COM指令执行的函数,解析函数我们发现向软件发送指令的是sendCmd函数;

      #  找到python封装好的COM函数
      def COM(self, args):
          self.sendCmd('COM', args)
          self.STATUS = int(self.getReply())
          self.READANS = self.getReply()
          self.COMANS = self.READANS[:]
          # self.COMANS = self.COMANS.strip()
          #solve the print message to terminal issues: some message can't be printed.
          print("")
          return self.STATUS
      

      进一步查看sendCmd函数及InCAM类,我们发现默认是通过"pipe(管道)"方式通讯的,检测到没有INCAM_USER这个环境变量或者透过终端交互时使用"socket(套接字)"通讯,这里我们只需要了解即可,学会使用及封装方法即可

      def sendCmd(self, cmd, args=''):
          self.blank()
          if self.comms == 'pipe':
              self.sendCommandToPipe(cmd, args)
          if self.comms == 'socket':
              self.sendCommandToSocket(cmd, args)
      

      根据官方提供的python接口,我们可以直接将add_pad指令按python代码来编写

      # !/usr/bin/env python3
      import sys
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam 
      
      # 实例化InCAM类
      Do = incam.InCAM()
      
      # 调用COM函数并将"add_pad指令及指令参数"当做一个参数传递给COM函数
      Do.COM("add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")
      
      sys.exit()
      

      我们将以上的代码保存成一个add_pnl_pad.py文本,在InCAMPro中运行查看效果
      在这里插入图片描述

  • 第二步,实现添加一个满足业务逻辑的pad代码:

    • 之前我们实现了添加pad代码功能,很显然这只是一个简单的功能实现,完全不满足我们实际的业务需求及程序设计要求,接下来我们添加脚本执行范围控制及实际的业务需求:
      1.脚本执行范围限制:
      我们必须要在料号step工作层别下执行添加pad的动作

      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam 
      
      # 实例化InCAM类
      Do = incam.InCAM()
      
      # 检测环境
      _job = os.environ.get('JOB', None)					# 获取内定环境变量JOB,没有获取到表示没有开启工作料号
      if not _job:
      	Do.PAUSE("请打开料号后再执行!")
      	sys.exit()
      	
      _stp = os.environ.get('STEP', None)					# 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
      if not _stp:
      	Do.PAUSE("请打开料号step后再执行!")
      	sys.exit()
      
      Do.COM('get_work_layer')
      _lay  = Do.COMANS									# 获取工作层别,没有获取到表示没有打开工作层
      if not _lay  :
      	Do.PAUSE("请打开层别后再执行!")
      	sys.exit()
      
      # 调用COM函数并将"add_pad指令及指令参数"当做一个参数传递给COM函数
      Do.COM("add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")
      
      sys.exit()
      

      查看效果
      在这里插入图片描述
      2.脚本业务逻辑设计:
      业务要求:在panel模块中添加一组工具孔;
      1)工具孔设计在通孔层别(dr),防焊层别需开窗设计(单边5mil),线路层别需无铜设计(距铜单边10mil),挡点层需阻止下油设计(单边3mil)
      2)工具孔大小3.175mm
      3)工具孔添加数量为4个;
      5)工具孔添加位置为板角;
      6)工具孔位置坐标参考拼板留边距离板边成型边5mm

      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam
      
      # 实例化InCAM类
      Do = incam.InCAM()
      
      # 检测环境
      _job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
      if not _job:
          Do.PAUSE("请打开料号后再执行!")
          sys.exit()
      
      _stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
      if not _stp or 'panel' not in _stp:
          Do.PAUSE("请打开料号panel后再执行!")
          sys.exit()
      
      # 获取料号matrix信息及所有的层别信息,以便判断所有的工作层及相关层是否存在(CAM开发基础专业知识)
      _drl_list = []
      _dot_list = []
      mask_list = []
      _sig_list = []
      _pow_list = []
      _matrix = Do.DO_INFO(f"-t matrix -e {_job}/matrix")
      i = 0
      while i < len(_matrix['gROWname']):
          if _matrix['gROWname'][i] in ['plug-c', 'plug-s']:
              _dot_list.append(_matrix['gROWname'][i])  # 获取挡点层(假设挡点以plug-c/s命名)
          if _matrix['gROWcontext'][i] == "board":
              if _matrix['gROWlayer_base_type'][i] in ['drill']:
                  _drl_list.append(_matrix['gROWname'][i])                # 获取所有board/drill属性的层(钻孔层)
              if _matrix['gROWlayer_base_type'][i] in ['solder_mask']:
                  mask_list.append(_matrix['gROWname'][i])                # 获取所有board/solder_mask属性的层(防焊层)
              if _matrix['gROWlayer_base_type'][i] in ['signal']:
                  _sig_list.append(_matrix['gROWname'][i])                # 获取所有board/signal属性的层(正片线路层)
              if _matrix['gROWlayer_base_type'][i] in ['power_ground']:
                  _pow_list.append(_matrix['gROWname'][i])                # 获取所有board/power_ground属性的层(负片线路层)
          i += 1
      
      # 添加规则解析
      """
      业务要求:在panel模块中添加一组工具孔;
      1)工具孔设计在通孔层别(dr),防焊层别需开窗设计(单边5mil),线路层别需无铜设计(距铜单边10mil),挡点层需阻止下油设计(单边3mil)
      2)工具孔大小3.175mm
      3)工具孔添加数量为4个;
      5)工具孔添加位置为板角;
      6)工具孔位置坐标参考拼板留边距离板边成型边5mm
      """
      
      # 1.添加层别判断
      _lay = "dr"  # 指定通孔钻孔层别是dr层
      if _lay not in _drl_list:
          Do.PAUSE("没有发现dr层,请检查层别是否存在或者属性设置是否正确!")        # 判断dr层是否ok
          sys.exit()
      
      # 2.添加孔大小指定
      _add_sym_size = "r3175"
      
      # 3.计算4个孔的添加坐标(根据所有虚拟拼板线距离零点的距离坐标)
      _pnl_dict = Do.DO_INFO(f"-t step -e {_job}/{_stp} -d PROF_LIMITS,units=mm")  # 返回一个获取到坐标数据的字典
      _x_min = float(_pnl_dict["gPROF_LIMITSxmin"])              # 虚拟拼板x方向距零点最近的坐标
      _x_max = float(_pnl_dict["gPROF_LIMITSxmax"])              # 虚拟拼板x方向距零点最远的坐标
      _y_min = float(_pnl_dict["gPROF_LIMITSymin"])              # 虚拟拼板y方向距零点最近的坐标
      _y_max = float(_pnl_dict["gPROF_LIMITSymax"])              # 虚拟拼板y方向距零点最远的坐标
      
      # 结合业务要求四个添加孔坐标定义(距离拼板成型线5mm)
      _x_l_d, _y_l_d = _x_min + 5, _y_min + 5         # 左下角孔坐标
      _x_r_d, _y_r_d = _x_max - 5, _y_min + 5         # 右下角孔坐标
      _x_l_u, _y_l_u = _x_min + 5, _y_max - 5         # 左上角孔坐标
      _x_r_u, _y_r_u = _x_max - 5, _y_max - 5         # 右上角孔坐标
      
      # 添加四个孔
      # 初始化(修改软件默认单位为mm)
      Do.COM("units,type=mm")
      
      # 初始化(关闭显示所有开启层别)
      Do.COM("affected_layer,mode=all,affected=no")
      Do.COM("clear_layers")
      
      # 开启工作层(dr)
      Do.COM(f"display_layer,name={_lay},display=yes,number=1")
      Do.COM(f"work_layer,name={_lay}")
      
      # 添加pad并带入参数
      for i in ((_x_l_d, _y_l_d), (_x_r_d, _y_r_d), (_x_l_u, _y_l_u), (_x_r_u, _y_r_u)):
          Do.COM(f"add_pad,attributes=no,x={i[0]},y={i[1]},"
                 f"symbol={_add_sym_size},polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")     # 实际参数说明需自行查看开发文档
      
      # 四个孔添加防焊开窗
      if len(mask_list) > 0:
          _size = 5 * 25.4 * 2        # 单边5mil转换为实际参数my直径
          Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(mask_list)},"
                 f"invert=no,dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")    # 实际参数说明需自行查看开发文档
      
      # 四个孔添加防焊挡点
      if len(_dot_list) > 0:
          _size = 3 * 25.4 * 2        # 单边3mil转换为实际参数my直径
          Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_dot_list)},"
                 f"invert=no,dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")    # 实际参数说明需自行查看开发文档
      
      # 四个孔制作线路无铜设计(正片线路)
      if len(_sig_list) > 0:
          _size = 10 * 25.4 * 2        # 单边10mil转换为实际参数my直径
          _inv = "yes"                 # 正片需要添加负极性pad制作成无铜区
          Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_sig_list)},"
                 f"invert={_inv},dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")    # 实际参数说明需自行查看开发文档
      
      # 四个孔制作线路无铜设计(正片线路)
      if len(_pow_list) > 0:
          _size = 10 * 25.4 * 2        # 单边10mil转换为实际参数my直径
          _inv = "no"                  # 负片需要添加正极性pad制作成无铜区
          Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_pow_list)},"
                 f"invert={_inv},dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")    # 实际参数说明需自行查看开发文档
      
      Do.PAUSE("程式执行完成,请检查!")
      sys.exit()
      
      

      查看效果
      在这里插入图片描述

  • 第三步,我们进一步封装代码:

    • 之前我们实现了满足业务逻辑的代码设计及编写,但是它不符合我们追求个性及高效的开发的要求,我们需要进一步设计代码程式:
      1.我不喜欢incam.py下的PAUSE提示框,我想一个有个性,更人性化的弹窗:
      首先,我们选择使用PyQt5作为ui设计的主模块,我们使用模块下的QMessageBox来封装一个我们喜欢的弹窗函数,先看原生弹窗如何在我们的代码中引用
      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      from PyQt5.QtWidgets import QMessageBox, QApplication  # 导入QMessageBox,QApplication
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam
      
      app = QApplication(sys.argv)        # PyQt界面设计必须加上这句代码
      
      # 实例化InCAM类
      Do = incam.InCAM()
      
      # 检测环境
      _job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
      if not _job:
          # Do.PAUSE("请打开料号后再执行!")
          QMessageBox.warning(None, "警告", "请打开料号后再执行!", QMessageBox.Ok)
          sys.exit()
      
      _stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
      if not _stp:
          # Do.PAUSE("请打开料号step后再执行!")
          QMessageBox.warning(None, "警告", "请打开料号step后再执行!", QMessageBox.Ok)
          sys.exit()
      
      Do.COM('get_work_layer')
      _lay = Do.COMANS  # 获取工作层别,没有获取到表示没有打开工作层
      if not _lay:
          # Do.PAUSE("请打开层别后再执行!")
          QMessageBox.warning(None, "警告", "请打开层别后再执行!", QMessageBox.Ok)
          sys.exit()
      
      # 调用COM函数并将"add_pad指令及指令参数"当做一个参数传递给COM函数
      Do.COM(
          "add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")
      
      sys.exit()
      
      执行效果如下
      在这里插入图片描述
      如上,我们实现了开箱即用的三方模块引用,但是显然并没有个性化可言,接下来我们更进一步,
      我们封装一个贴近所有人常识的弹窗函数,我们遵循红绿黄灯通行原则,红窗停,绿窗行,黄窗弹出等一等,接下来看我们如何封装
      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      from PyQt5 import QtCore, QtGui                         # 导入我们封装弹窗用到的QtCore, QtGui
      from PyQt5.QtWidgets import QMessageBox, QApplication   # 导入QMessageBox,QApplication
      from PyQt5.QtCore import Qt                             # 导入我们封装弹窗用到的Qt
      from PyQt5.QtGui import QPixmap                         # 导入我们封装弹窗用到的QPixmap
      
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam
      
      
      def warningbox(**args):
          """
          警告信息弹窗(黄灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.warningbox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "警告信息", 'None', "/warning.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#FFFF00;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
      
      
      def errorbox(**args):
          """
          错误信息弹窗(红灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.errorbox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "错误信息", 'None', "/guierror.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#FF3300;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
      
      
      def infobox(**args):
          """
          提示信息弹窗(绿灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.infobox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "提示信息", 'None', "/guiinfo.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#33CC33;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
      
      
      app = QApplication(sys.argv)        # PyQt界面设计必须加上这句代码
      
      # 实例化InCAM类
      Do = incam.InCAM()
      
      # 检测环境
      _job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
      if not _job:
          # Do.PAUSE("请打开料号后再执行!")
          # QMessageBox.warning(None, "警告", "请打开料号后再执行!", QMessageBox.Ok)
          errorbox(mess="请打开料号后再执行!")
          sys.exit()
      
      _stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
      if not _stp:
          # Do.PAUSE("请打开料号step后再执行!")
          # QMessageBox.warning(None, "警告", "请打开料号step后再执行!", QMessageBox.Ok)
          errorbox(mess="请打开料号step后再执行!")
          sys.exit()
      
      Do.COM('get_work_layer')
      _lay = Do.COMANS  # 获取工作层别,没有获取到表示没有打开工作层
      if not _lay:
          # Do.PAUSE("请打开层别后再执行!")
          # QMessageBox.warning(None, "警告", "请打开层别后再执行!", QMessageBox.Ok)
          errorbox(mess="请打开层别后再执行!")
          sys.exit()
      
      # 调用COM函数并将"add_pad指令及指令参数"当做一个参数传递给COM函数
      Do.COM(
          "add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")
      
      sys.exit()
      
      执行效果如下,这样我们就可以灵活的选择弹窗样式,从生活常识人性化的角度去个性化我们的代码设计,潜移默化的培养用户习惯
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      2.incam.py下的函数封装太初级,我们每次调用函数需要编写一大堆的无效参数,既不方便又显得代码很臃肿,不方便维护,我们怎么办,那就在封装:
      我们以add_pad这个指令封装为例,查看代码:
      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      from PyQt5 import QtCore, QtGui                         # 导入我们封装弹窗用到的QtCore, QtGui
      from PyQt5.QtWidgets import QMessageBox, QApplication   # 导入QMessageBox,QApplication
      from PyQt5.QtCore import Qt                             # 导入我们封装弹窗用到的Qt
      from PyQt5.QtGui import QPixmap                         # 导入我们封装弹窗用到的QPixmap
      
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam
      
      
      # 封装一个自定义的警告信息弹窗
      def warningbox(**args):
          """
          警告信息弹窗(黄灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.warningbox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "警告信息", 'None', "/warning.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#FFFF00;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
      
      
      # 封装一个自定义的错误信息弹窗
      def errorbox(**args):
          """
          错误信息弹窗(红灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.errorbox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "错误信息", 'None', "/guierror.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#FF3300;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
      
      
      # 封装一个自定义的提示信息弹窗
      def infobox(**args):
          """
          提示信息弹窗(绿灯)
          :param args:   不定长参数
                          title="温馨提示",
                          mess='None'
          :return: 无
          使用例子: Gui.infobox(title="温馨提示", mess='None')
          """
          images_path = "/incam/server//site_data/scripts/py3_package/icon"  # 将我们要使用的图片图标放置在这里
          title, mess, icon = "提示信息", 'None', "/guiinfo.png"
          for key in args:
              if key == 'title':
                  title = args['title']
              if key == 'mess':
                  mess = args['mess']
              if key == 'icon':
                  icon = args['icon']
          emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                         "text-align:center; font-family:AR PL UMing CN;\"> "
                                                         f"<strong>{mess}</strong> </span>")  # 使用超文本显示提示信息
          emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶弹窗
          emeg.setStandardButtons(QMessageBox.Yes)                            # 给弹窗放一个yes按钮
          emeg.button(QMessageBox.Yes).setText("确认")                                          # 修改按钮显示为中文"确认"
          emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(images_path + "/ok_.png"))     # 为按钮添加一个图标
          emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))                      # 设置图标显示大小
          emeg.setIconPixmap(QPixmap(images_path + icon))                                # 在窗体上添加一个图片(警告图片)
          emeg.setWindowIcon(QtGui.QIcon(images_path + "/NccIcon.png"))                  # 给弹窗加一个任务栏图标
          emeg.setStyleSheet("QMessageBox {background:#33CC33;}"
                             "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                             "beige;color:#EEEEEE;font: bold 16px;font-family:AR PL UMing CN;min-width: 5em;min-height: 2em;}"
                             "QPushButton:hover{background:#990000; color:white}")            # 设置弹窗样式
          emeg.show()
          emeg.exec_()
          
      
      # 封装一个自定义的InCAMPro添加pad函数
      def add_pad(symbol, xcoord, ycoord, **args):
          """
          添加pad
          :param symbol: 要添加的symbol
          :param xcoord: X坐标
          :param ycoord: Y坐标
          :param args:   不定长参数
                          attributes='yes/no',
                          attribute='.string',
                          text='fangxiangkong',
                          polarity='positive/negative',
                          angle='0',
                          mirror='yes/no',
                          xnumber ='1',
                          ynumber ='1',
                          xspacing ='0',
                          yspacing ='0',
                          xscale ='1',
                          yscale ='1'
          :return: 无
          使用例子: Do.addpad(symbol, xcoord, ycoord, attributes='yes', attribute='.string', text='fangxiangkong')
          """
          # 实例化InCAM类
          _do = incam.InCAM()
          symbol, xcoord, ycoord = str(symbol), str(xcoord), str(ycoord)
          attributes, attribute, text, option, _int = 'no', '.string', 'none', 'none', 'none'
          polarity, angle, mirror = 'positive', '0', 'no'
          xnumber, ynumber = '1', '1'
          xspacing, yspacing = '0', '0'
          xscale, yscale = '1', '1'
          attr_text = []
          for key in args:
              if key == 'attributes':
                  attributes = str(args['attributes'])
              if key == 'attribute':
                  attribute = args['attribute']
              if key == 'text':
                  text = str(args['text'])
              if key == 'option':
                  option = str(args['option'])
              if key == '_int':
                  _int = str(args['_int'])
              if key == 'polarity':
                  polarity = str(args['polarity'])
              if key == 'angle':
                  angle = str(args['angle'])
              if key == 'mirror':
                  mirror = str(args['mirror'])
              if key == 'xnumber':
                  xnumber = str(args['xnumber'])
              if key == 'ynumber':
                  ynumber = str(args['ynumber'])
              if key == 'xspacing':
                  xspacing = str(args['xspacing'])
              if key == 'yspacing':
                  yspacing = str(args['yspacing'])
              if key == 'xscale':
                  xscale = str(args['xscale'])
              if key == 'yscale':
                  yscale = str(args['yscale'])
              if key == 'attr_text':
                  attr_text = args['attr_text']
      
          _do.COM("cur_atr_reset")
          if len(attr_text) == 0:
              if isinstance(attribute, list):
                  for arr in attribute:
                      _do.COM(f"cur_atr_set,attribute={arr},text={text},option={option}")
              else:
                  if _int not in ["none"]:
                      _do.COM(f"cur_atr_set,attribute={attribute},int={_int}")
                  else:
                      if option == 'none':
                          _do.COM(f"cur_atr_set,attribute={attribute},text={text}")
                      else:
                          _do.COM(f"cur_atr_set,attribute={attribute},text={text},option={option}")
          else:
              for a in attr_text:
                  _do.COM(f"cur_atr_set,attribute={a[0]},text={a[1]}")
          _do.COM("skip_next_pre_hook")       # 忽略前置hooks
          _do.COM(f"add_pad,"
                  f"attributes={attributes},"
                  f"x={xcoord},y={ycoord},"
                  f"symbol={symbol},"
                  f"polarity={polarity},"
                  f"angle={angle},"
                  f"mirror={mirror},"
                  f"nx={xnumber},ny={ynumber},"
                  f"dx={xspacing},dy={yspacing},"
                  f"xscale={xscale},yscale={yscale}"
                  )
          _do.COM("cur_atr_reset")
      
      if __name__ == "__main__":
      	app = QApplication(sys.argv)        # PyQt界面设计必须加上这句代码
      	
      	# 实例化InCAM类
      	Do = incam.InCAM()
      	
      	# 检测环境
      	_job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
      	if not _job:
      	    # Do.PAUSE("请打开料号后再执行!")                # 使用InCAM类自带的PAUSE弹窗
      	    # QMessageBox.warning(None, "警告", "请打开料号后再执行!", QMessageBox.Ok)     # 使用PyQt5弹窗
      	    errorbox(mess="请打开料号后再执行!")             # 使用我们利用PyQt5弹窗模块自行封装的弹窗
      	    sys.exit()
      	
      	_stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
      	if not _stp:
      	    # Do.PAUSE("请打开料号step后再执行!")
      	    # QMessageBox.warning(None, "警告", "请打开料号step后再执行!", QMessageBox.Ok)
      	    errorbox(mess="请打开料号step后再执行!")
      	    sys.exit()
      	
      	Do.COM('get_work_layer')
      	_lay = Do.COMANS  # 获取工作层别,没有获取到表示没有打开工作层
      	if not _lay:
      	    # Do.PAUSE("请打开层别后再执行!")
      	    # QMessageBox.warning(None, "警告", "请打开层别后再执行!", QMessageBox.Ok)
      	    errorbox(mess="请打开层别后再执行!")
      	    sys.exit()
      	
      	# 调用COM函数并将"add_pad指令及指令参数"当做一个参数传递给COM函数
      	# Do.COM("add_pad,attributes=no,x=0,y=0,symbol=r100,polarity=positive,angle=0,mirror=no,nx=1,ny=1,dx=0,dy=0,xscale=1,yscale=1")
      	add_pad(symbol="r100", xcoord="0", ycoord="0")  # 使用我们自己封装的代码添加一个pad,除了需要我们指定的必要参数,其他参数可以默认,同时也支持随时修改参数
      	
      	sys.exit()
      
      
      更进一步,我们的代码还是很长且代码不能复用,接下来我们再封装,实现模块化满足业务逻辑分离,我们将常用的函数封装成一个独立可复用的模块(class),直接上代码:
      弹窗模块GuiClass.py
      #!/usr/bin/env py3k
      
      from PyQt5 import QtCore, QtGui                         # 导入我们封装弹窗用到的QtCore, QtGui
      from PyQt5.QtWidgets import QMessageBox, QApplication   # 导入QMessageBox,QApplication
      from PyQt5.QtCore import Qt                             # 导入我们封装弹窗用到的Qt
      from PyQt5.QtGui import QPixmap                         # 导入我们封装弹窗用到的QPixmap
      
      # 开发日志
      _header = {
         '脚本名称': 'GuiClass弹窗类',
         '开发人员': 'Twei Tang',
         '开发时间': '2025年11月26日',
         '版本信息': 'A.1.0',
         '联系方式': (
             '邮箱地址<>',
             '微信号码<358143105>',
             '手机号码<13627441202>'
         ),
         '开发信息': (
             '无'
         ),
         '修改信息': (
             '当前版本(A.1.0),首次开发测试,暂无版本变更信息'
         ),
         '沟通记录': (
             '无'
         )
      }
      
      
      class MainGui:
         def __init__(self):
             self.images_path = "/incam/server/site_data/scripts/py3_package/icon"
             self.font = 'AR PL UMing CN'
      
         def warningbox(self, **args):
             """
             警告信息弹窗
             :param args:   不定长参数
                             title="温馨提示",
                             mess='None'
             :return: 无
             使用例子: Gui.warningbox(title="温馨提示", mess='None')
             """
             title, mess, icon = "警告信息", 'None', "/warning.png"
             for key in args:
                 if key == 'title':
                     title = args['title']
                 if key == 'mess':
                     mess = args['mess']
                 if key == 'icon':
                     icon = args['icon']
             emeg = QMessageBox(QMessageBox.Warning, title, "<span style=\"color:#3C3F41;font-size:18px; "
                                                            "text-align:center; font-family:%s;\"> "
                                                            "<strong>%s</strong> </span>" % (self.font, mess))
             emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶窗口
             emeg.setStandardButtons(QMessageBox.Yes)
             emeg.button(QMessageBox.Yes).setText("确认")
             emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(self.images_path + "/ok_.png"))
             emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))
             emeg.setIconPixmap(QPixmap(self.images_path + icon))
             emeg.setWindowIcon(QtGui.QIcon(self.images_path + "/NccIcon.png"))
             emeg.setStyleSheet("QMessageBox {background:#FFFF00;}"
                                "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                                "beige;color:#EEEEEE;font: bold 16px;font-family:%s;min-width: 5em;min-height: 2em;}"
                                "QPushButton:hover{background:#990000; color:white}" % self.font)
             emeg.show()
             emeg.exec_()
      
         def infobox(self, **args):
             """
             提示信息弹窗
             :param args:   不定长参数
                             title="温馨提示",
                             mess='None'
             :return: 无
             使用例子: Gui.infobox(title="提示信息", mess='None')
             """
             title, mess, icon = "提示信息", 'None', "/guiinfo.png"
             for key in args:
                 if key == 'title':
                     title = args['title']
                 if key == 'mess':
                     mess = args['mess']
                 if key == 'icon':
                     icon = args['icon']
             emeg = QMessageBox(QMessageBox.Information, title, "<span style=\"color:#3C3F41;font-size: 18px; "
                                                                "text-align:center; font-family:%s;\"><strong>%s</strong>"
                                                                "</span>" % (self.font, mess))
             emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶窗口
             emeg.setStandardButtons(QMessageBox.Yes)
             emeg.button(QMessageBox.Yes).setText("确认")
             emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(self.images_path + "/ok_.png"))
             emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 20))
             emeg.setIconPixmap(QPixmap(self.images_path + icon))
             emeg.setWindowIcon(QtGui.QIcon(self.images_path + "/NccIcon.png"))
             emeg.setStyleSheet("QMessageBox {background:#33CC33;}"
                                "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                                "beige;color:#EEEEEE;font: bold 16px;font-family:%s;min-width: 5em;min-height: 2em;}"
                                "QPushButton:hover{background:#990000; color:white}" % self.font)
             emeg.show()
             emeg.exec_()
      
         def errorbox(self, **args):
             """
             错误信息弹窗
             :param args:   不定长参数
                             title="温馨提示",
                             mess='None'
             :return: 无
             使用例子: Gui.errorbox(title="提示信息", mess='None')
             """
             title, mess, icon = "错误信息", 'None', "/guierror.png"
             for key in args:
                 if key == 'title':
                     title = args['title']
                 if key == 'mess':
                     mess = args['mess']
                 if key == 'icon':
                     icon = args['icon']
             emeg = QMessageBox(QMessageBox.Information, title, "<span style=\"color:#3C3F41;font-size:18px;"
                                                                "text-align:center;font-family:%s;\">"
                                                                "<strong>%s</strong></span>" % (self.font, mess))
             emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶窗口
             emeg.setStandardButtons(QMessageBox.Yes)
             emeg.button(QMessageBox.Yes).setText("确认")
             emeg.button(QMessageBox.Yes).setIcon(QtGui.QIcon(self.images_path + "/ok_.png"))
             emeg.button(QMessageBox.Yes).setIconSize(QtCore.QSize(20, 30))
             emeg.setIconPixmap(QPixmap(self.images_path + icon))
             emeg.setWindowIcon(QtGui.QIcon(self.images_path + "/NccIcon.png"))
             emeg.setStyleSheet("QMessageBox {background:#FF3300;}"
                                "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                                "beige;color:#EEEEEE;font: bold 16px;font-family:%s;min-width: 5em;min-height: 2em;}"
                                "QPushButton:hover{background:#990000; color:white}" % self.font)
             emeg.show()
             emeg.exec_()
      
         def questionbox(self, **args):
             """
             问题信息弹窗
             :param args:   不定长参数
                             title="温馨提示",
                             mess='None'
             :return: yes/no
             使用例子: Gui.questionbox(title="问题信息", mess='None')
             更改: 20240513 增加_opt options
             """
             title, mess, icon, order = "问题信息", 'None', "/guiquestion.png", False
             def_but = "no"
             options = ["yes", "no"]
             for key in args:
                 if key == 'title':
                     title = args['title']
                 if key == 'mess':
                     mess = args['mess']
                 if key == 'icon':
                     icon = args['icon']
                 if key == 'def_but':
                     def_but = args['def_but']
                 if key == 'options':
                     options = args['options']
                 if key == 'order':     # 暂时解决锣带按钮排布问题待后续处理
                     order = args['order']
             emeg = QMessageBox(QMessageBox.Question, title, "<span style=\"color:#3C3F41;font-size:18px;"
                                                             "text-align:center;font-family:%s;\">"
                                                             "<strong>%s</strong></span>" % (self.font, mess))
             emeg.setWindowFlags(emeg.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置为置顶窗口
             if def_but == "no":
                 emeg.addButton("确认", QMessageBox.YesRole)
                 emeg.addButton("取消", QMessageBox.NoRole)
             elif def_but == "_lock":
                 emeg.addButton("解锁", QMessageBox.YesRole)
                 emeg.addButton("上锁", QMessageBox.NoRole)
             elif def_but == "_mnjob":
                 emeg.addButton("M 型号", QMessageBox.YesRole)
                 emeg.addButton("N 型号", QMessageBox.NoRole)
             elif def_but == "_misc":
                 emeg.addButton("备份", QMessageBox.YesRole)
                 emeg.addButton("还原", QMessageBox.NoRole)
             elif def_but == "_ld":
                 emeg.addButton("cs-ld", QMessageBox.YesRole)
                 emeg.addButton("ss-ld", QMessageBox.NoRole)
             elif def_but == "_hen":
                 emeg.addButton("横向", QMessageBox.YesRole)
                 emeg.addButton("竖向", QMessageBox.NoRole)
             elif def_but == "_opt":
                 emeg.addButton(options[0], QMessageBox.YesRole)
                 emeg.addButton(options[1], QMessageBox.NoRole)
             elif def_but == "resu":
                 emeg.addButton("继续", QMessageBox.YesRole)
                 emeg.addButton("退出", QMessageBox.NoRole)
             else:
                 emeg.addButton("是", QMessageBox.YesRole)
                 emeg.addButton("否", QMessageBox.NoRole)
      
             emeg.setIconPixmap(QPixmap(self.images_path + icon))
             emeg.setWindowIcon(QtGui.QIcon(self.images_path + "/NccIcon.png"))
             emeg.setStyleSheet("QMessageBox {background:#FFFF00;}"
                                "QPushButton {background-color:#333333;border-width: 1px;border-radius: 0px;border-color: "
                                "beige;color:#EEEEEE;font: bold 16px;font-family:%s;min-width: 5em;min-height: 2em;}"
                                "QPushButton:hover{background:#990000; color:white}" % self.font)
             emeg.show()
             buttype = emeg.exec_()
      
             if order:
                 if buttype == 1:
                     return "yes"
                 elif buttype == 0:
                     return "no"
      
             if buttype == 1:
                 return "no"
             elif buttype == 0:
                 return "yes"
      
      
      InCAMPro指令模块LCMClass.py
      #!/usr/bin/env py3k
      
      import sys
      
      # 导入官方的incam.py接口
      sys.path.append("/incam/release/app_data/python")
      import incam
      
      # 开发日志
      _header = {
         '脚本名称': 'InCAMPro指令类',
         '开发人员': 'Twei Tang',
         '开发时间': '2025年11月26日',
         '版本信息': 'A.1.0',
         '联系方式': (
             '邮箱地址<>',
             '微信号码<358143105>',
             '手机号码<13627441202>'
         ),
         '开发信息': (
             '无'
         ),
         '修改信息': (
             '当前版本(A.1.0),首次开发测试,暂无版本变更信息'
         ),
         '沟通记录': (
             '无'
         )
      }
      
      
      class MainLCM(incam.InCAM):     # 继承incam.py下的InCAM类,当前类可以直接调用incam.py下的InCAM类的所有函数等
         def __init__(self):
             incam.InCAM.__init__(self)
             self.do = incam.InCAM()
      
         def add_pad(self, symbol, xcoord, ycoord, **args):
             """
             添加pad
             :param symbol: 要添加的symbol
             :param xcoord: X坐标
             :param ycoord: Y坐标
             :param args:   不定长参数
                             attributes='yes/no',
                             attribute='.string',
                             text='fangxiangkong',
                             polarity='positive/negative',
                             angle='0',
                             mirror='yes/no',
                             xnumber ='1',
                             ynumber ='1',
                             xspacing ='0',
                             yspacing ='0',
                             xscale ='1',
                             yscale ='1'
             :return: 无
             使用例子: Do.addpad(symbol, xcoord, ycoord, attributes='yes', attribute='.string', text='fangxiangkong')
             """
             symbol, xcoord, ycoord = str(symbol), str(xcoord), str(ycoord)
             attributes, attribute, text, option, _int = 'no', '.string', 'none', 'none', 'none'
             polarity, angle, mirror = 'positive', '0', 'no'
             xnumber, ynumber = '1', '1'
             xspacing, yspacing = '0', '0'
             xscale, yscale = '1', '1'
             attr_text = []
             for key in args:
                 if key == 'attributes':
                     attributes = str(args['attributes'])
                 if key == 'attribute':
                     attribute = args['attribute']
                 if key == 'text':
                     text = str(args['text'])
                 if key == 'option':
                     option = str(args['option'])
                 if key == '_int':
                     _int = str(args['_int'])
                 if key == 'polarity':
                     polarity = str(args['polarity'])
                 if key == 'angle':
                     angle = str(args['angle'])
                 if key == 'mirror':
                     mirror = str(args['mirror'])
                 if key == 'xnumber':
                     xnumber = str(args['xnumber'])
                 if key == 'ynumber':
                     ynumber = str(args['ynumber'])
                 if key == 'xspacing':
                     xspacing = str(args['xspacing'])
                 if key == 'yspacing':
                     yspacing = str(args['yspacing'])
                 if key == 'xscale':
                     xscale = str(args['xscale'])
                 if key == 'yscale':
                     yscale = str(args['yscale'])
                 if key == 'attr_text':
                     attr_text = args['attr_text']
      
             self.do.COM("cur_atr_reset")
             if len(attr_text) == 0:
                 if isinstance(attribute, list):
                     for arr in attribute:
                         self.do.COM(f"cur_atr_set,attribute={arr},text={text},option={option}")
                 else:
                     if _int not in ["none"]:
                         self.do.COM(f"cur_atr_set,attribute={attribute},int={_int}")
                     else:
                         if option == 'none':
                             self.do.COM(f"cur_atr_set,attribute={attribute},text={text}")
                         else:
                             self.do.COM(f"cur_atr_set,attribute={attribute},text={text},option={option}")
             else:
                 for a in attr_text:
                     self.do.COM(f"cur_atr_set,attribute={a[0]},text={a[1]}")
             self.do.COM("skip_next_pre_hook")  # 忽略前置hooks
             self.do.COM(f"add_pad,"
                         f"attributes={attributes},"
                         f"x={xcoord},y={ycoord},"
                         f"symbol={symbol},"
                         f"polarity={polarity},"
                         f"angle={angle},"
                         f"mirror={mirror},"
                         f"nx={xnumber},ny={ynumber},"
                         f"dx={xspacing},dy={yspacing},"
                         f"xscale={xscale},yscale={yscale}"
                         )
             self.do.COM("cur_atr_reset")
      
      
      使用自定义模块化后的代码如下(整个代码简洁清晰):
      #!/usr/bin/env python3
      
      # 导入我们所需的系统包或者第三方包
      import sys
      import os
      from PyQt5.QtWidgets import QApplication   # 导入QMessageBox,QApplication
      
      
      # 导入我们自己封装的GuiClass.py接口(假设就放在当前脚本相同目录,不同目录直接指定导入目录即可)
      # sys.path.append("你的GuiClass.py存放目录")
      import GuiClass
      
      # 导入我们自己封装的LCMClass.py接口(假设就放在当前脚本相同目录,不同目录直接指定导入目录即可)
      # sys.path.append("你的LCMClass.py存放目录")
      import LCMClass
      
      
      if __name__ == "__main__":
          app = QApplication(sys.argv)        # PyQt界面设计必须加上这句代码
      
          # 实例化GuiClass类
          Gui = GuiClass.MainGui()
      
          # 实例化LCMClass类
          Do = LCMClass.MainLCM()
      
          # 检测环境
          _job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
          if not _job:
              Gui.errorbox(mess="请打开料号后再执行!")           # 使用我们自定义的弹窗复用模块
              sys.exit()
      
          _stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
          if not _stp:
              Gui.errorbox(mess="请打开料号step后再执行!")  # 使用我们自定义的弹窗复用模块
              sys.exit()
      
          Do.COM('get_work_layer')
          _lay = Do.COMANS  # 获取工作层别,没有获取到表示没有打开工作层
          if not _lay:
              Gui.errorbox(mess="请打开层别后再执行!")  # 使用我们自定义的弹窗复用模块
              sys.exit()
      
          Do.add_pad(symbol="r100", xcoord="0", ycoord="0")  # 使用我们自定义的InCAMPro指令复用模块
      
          sys.exit()
      
      

最后,我们看看完全设计后的完整代码(到这里你能自己动手封装代码中没有进一步封装的函数吗?)

#!/usr/bin/env python3

# 导入我们所需的系统包或者第三方包
import sys
import os
from PyQt5.QtWidgets import QApplication   # 导入QApplication


# 导入我们自己封装的GuiClass.py接口(假设就放在当前脚本相同目录,不同目录直接指定导入目录即可)
# sys.path.append("你的GuiClass.py存放目录")
import GuiClass

# 导入我们自己封装的LCMClass.py接口(假设就放在当前脚本相同目录,不同目录直接指定导入目录即可)
# sys.path.append("你的LCMClass.py存放目录")
import LCMClass

# 开发日志
_header = {
    '脚本名称': 'panel自动添加pin孔程式',
    '开发人员': 'Twei Tang',
    '开发时间': '2025年11月26日',
    '版本信息': 'A.1.0',
    '联系方式': (
        '邮箱地址<>',
        '微信号码<358143105>',
        '手机号码<13627441202>'
    ),
    '开发信息': (
        '无'
    ),
    '修改信息': (
        '当前版本(A.1.0),首次开发测试,暂无版本变更信息'
    ),
    '沟通记录': (
        """
        # 添加规则解析
        业务要求:在panel模块中添加一组工具孔;
        1)工具孔设计在通孔层别(dr),防焊层别需开窗设计(单边5mil),线路层别需无铜设计(距铜单边10mil),挡点层需阻止下油设计(单边3mil)
        2)工具孔大小3.175mm
        3)工具孔添加数量为4个;
        5)工具孔添加位置为板角;
        6)工具孔位置坐标参考拼板留边距离板边成型边5mm
        """
    )
}


def _main():
    app = QApplication(sys.argv)  # PyQt界面设计必须加上这句代码

    # 实例化GuiClass类
    Gui = GuiClass.MainGui()

    # 实例化LCMClass类
    Do = LCMClass.MainLCM()

    # 检测环境
    _job = os.environ.get('JOB', None)  # 获取内定环境变量JOB,没有获取到表示没有开启工作料号
    if not _job:
        Gui.errorbox(mess="请打开料号后再执行!")  # 使用我们自定义的弹窗复用模块
        sys.exit()

    _stp = os.environ.get('STEP', None)  # 获取内定环境变量STEP,没有获取到表示没有开启工作料号step
    if not _stp or 'panel' not in _stp:
        Gui.errorbox(mess="请打开料号panel后再执行!")  # 使用我们自定义的弹窗复用模块
        sys.exit()

    # 获取料号matrix信息及所有的层别信息,以便判断所有的工作层及相关层是否存在(CAM开发基础专业知识)
    _drl_list = []
    _dot_list = []
    mask_list = []
    _sig_list = []
    _pow_list = []
    _matrix = Do.DO_INFO(f"-t matrix -e {_job}/matrix")
    i = 0
    while i < len(_matrix['gROWname']):
        if _matrix['gROWname'][i] in ['plug-c', 'plug-s']:
            _dot_list.append(_matrix['gROWname'][i])  # 获取挡点层(假设挡点以plug-c/s命名)
        if _matrix['gROWcontext'][i] == "board":
            if _matrix['gROWlayer_base_type'][i] in ['drill']:
                _drl_list.append(_matrix['gROWname'][i])  # 获取所有board/drill属性的层(钻孔层)
            if _matrix['gROWlayer_base_type'][i] in ['solder_mask']:
                mask_list.append(_matrix['gROWname'][i])  # 获取所有board/solder_mask属性的层(防焊层)
            if _matrix['gROWlayer_base_type'][i] in ['signal']:
                _sig_list.append(_matrix['gROWname'][i])  # 获取所有board/signal属性的层(正片线路层)
            if _matrix['gROWlayer_base_type'][i] in ['power_ground']:
                _pow_list.append(_matrix['gROWname'][i])  # 获取所有board/power_ground属性的层(负片线路层)
        i += 1

    # 1.添加层别判断
    _lay = "dr"  # 指定通孔钻孔层别是dr层
    if _lay not in _drl_list:
        Gui.errorbox(mess="没有发现dr层,请检查层别是否存在或者属性设置是否正确!")  # 判断dr层是否ok
        sys.exit()

    # 2.添加孔大小指定
    _add_sym_size = "r3175"

    # 3.计算4个孔的添加坐标(根据所有虚拟拼板线距离零点的距离坐标)
    _pnl_dict = Do.DO_INFO(f"-t step -e {_job}/{_stp} -d PROF_LIMITS,units=mm")  # 返回一个获取到坐标数据的字典
    _x_min = float(_pnl_dict["gPROF_LIMITSxmin"])  # 虚拟拼板x方向距零点最近的坐标
    _x_max = float(_pnl_dict["gPROF_LIMITSxmax"])  # 虚拟拼板x方向距零点最远的坐标
    _y_min = float(_pnl_dict["gPROF_LIMITSymin"])  # 虚拟拼板y方向距零点最近的坐标
    _y_max = float(_pnl_dict["gPROF_LIMITSymax"])  # 虚拟拼板y方向距零点最远的坐标

    # 结合业务要求四个添加孔坐标定义(距离拼板成型线5mm)
    _x_l_d, _y_l_d = _x_min + 5, _y_min + 5  # 左下角孔坐标
    _x_r_d, _y_r_d = _x_max - 5, _y_min + 5  # 右下角孔坐标
    _x_l_u, _y_l_u = _x_min + 5, _y_max - 5  # 左上角孔坐标
    _x_r_u, _y_r_u = _x_max - 5, _y_max - 5  # 右上角孔坐标

    # 添加四个孔
    # 初始化(修改软件默认单位为mm)
    Do.COM("units,type=mm")

    # 初始化(关闭显示所有开启层别)
    Do.COM("affected_layer,mode=all,affected=no")
    Do.COM("clear_layers")

    # 开启工作层(dr)
    Do.COM(f"display_layer,name={_lay},display=yes,number=1")
    Do.COM(f"work_layer,name={_lay}")

    # 添加pad并带入参数
    for i in ((_x_l_d, _y_l_d), (_x_r_d, _y_r_d), (_x_l_u, _y_l_u), (_x_r_u, _y_r_u)):
        Do.add_pad(symbol=_add_sym_size, xcoord=i[0], ycoord=i[1])  # 使用我们自定义的InCAMPro指令复用模块

    # 四个孔添加防焊开窗
    if len(mask_list) > 0:
        _size = 5 * 25.4 * 2  # 单边5mil转换为实际参数my直径
        Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(mask_list)},"
               f"invert=no,dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")  # 同add_pad,你能自己封装这个函数吗?

    # 四个孔添加防焊挡点
    if len(_dot_list) > 0:
        _size = 3 * 25.4 * 2  # 单边3mil转换为实际参数my直径
        Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_dot_list)},"
               f"invert=no,dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")

    # 四个孔制作线路无铜设计(正片线路)
    if len(_sig_list) > 0:
        _size = 10 * 25.4 * 2  # 单边10mil转换为实际参数my直径
        _inv = "yes"  # 正片需要添加负极性pad制作成无铜区
        Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_sig_list)},"
               f"invert={_inv},dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")

    # 四个孔制作线路无铜设计(正片线路)
    if len(_pow_list) > 0:
        _size = 10 * 25.4 * 2  # 单边10mil转换为实际参数my直径
        _inv = "no"  # 负片需要添加正极性pad制作成无铜区
        Do.COM(f"sel_copy_other,dest=layer_name,target_layer={';'.join(_pow_list)},"
               f"invert={_inv},dx=0,dy=0,size={_size},x_anchor=0,y_anchor=0,rotation=0,mirror=none")

    Gui.infobox(mess="程式执行完成,请检查!")
    sys.exit()


if __name__ == "__main__":
    _main()


本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值