/* NAME: DESCRIPTION: 钻孔输出; PARAMETER: [ { name : 'step_filter', title : '工作step', type : 'LineEdit', property : {tool_tip : '过滤Step名称'}, }, { name : 'out_dir', title : '钻孔输出路径', type : 'LineEdit', property : {tool_tip : '例如: /output/drill'}, }, { name : 'cool_spread', title : '跳钻距离(um)', type : 'LineEdit', property : {tool_tip : '例如: 350'}, }, { name : 'reread_layer', type : 'RadioBox', title : '回读钻孔程式', property : {tool_tip:'未设定,则默认no', size_policy:'Expanding,Fixed',item_list:[{name:'yes',text:'Yes'},{name:'no',text:'No'}]}, pack : {row:1,column:1}, }, { name : 'is_select_lyr', type : 'RadioBox', title : '是否选择层别', property : {tool_tip:'未设定,则默认no', size_policy:'Expanding,Fixed',item_list:[{name:'yes',text:'Yes'},{name:'no',text:'No'}]}, pack : {row:1,column:1}, }, { name : 'auto_save', title : '自动保存', type : 'RadioBox', property : { item_list:[ {name:'yes',text:'YES'}, {name:'no',text:'NO'}, ], tool_tip:'是否自动保存料号开关' } } ] VERSION_HISTORY: V1.00 2020-09-01 Scott Sun 1.新版本 HELP:

功能简介

生成导气板及输出


参数配置

step信息


注意事项


*/ ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// console.log("==============================>template"); // 引入模块 包 var $ = require('topcam.scriptfunc').argv(); var fs = require('fs'); var _ = require('lodash'); var mode = $.ikm ? "topcam" : "aimdfm"; var IKM = $.ikm; if (IKM==undefined ) { IKM = require('topcam.ikm6')($) } var GEN = $.gen; var GUI = $.gui || {}; var Job = $.job || $.job_name; var JobId = $.job_id; var db = $.db || IKM.db var PAR = {} if ($.par) { PAR = $.par } else if ($.hasOwnProperty('script_parameter')){ PAR = JSON.parse($.script_parameter); } if (mode === "aimdfm") { var database = require("topsin.database"); database.addConnection($.conf.database_conf, "DFM"); var QDfm = database.query("DFM"); $.QDfm = QDfm; if ($.conf.product_type == "aimdfm") { QDfm.updateRow({ table: "pdm_aimdfm_task", data: { current_process_title: $.process_title }, where: { id: $.task_id } }); } } require("topsin.genmath") var genMath = new GenMath(); var gui = new NewGUI(GUI); var Status = 'ok'; var resultData = []; var par = PAR; var default_par = { spread: 2000, step_filter:"step", out_dir:"C:/Users/Administrator/Desktop/jobs/demo", cool_spread:350, reread_layer:"no", is_select_lyr:"no", auto_save: "No", units:"mm" } for(var key in default_par){ if (!par.hasOwnProperty(key) || par[key] == ""){ par[key] = default_par[key] }} var job = Job; var info = {}; var new_name = "new_test"; if(!fs.exists(par.out_dir)){ IKM.msg("导出路径不存在"); return "Canel" } par.out_dir += '/' + new_name; fs.mkdir(par.out_dir); var Step; try { if(_.isEmpty(job)){throw "参数job不存在"} else { job = job.toLowerCase() } if(!GEN.isJobExists({job:job})){throw "料号"+job+"不存在"} // 选择工作step var workstep = getWorkStep() if(workstep.length == 0){throw "未找到工作step"} // 选择工作层 var work_layers = select_work_layer(); if(work_layers.length == 0){throw "未找到工作层"} // 确认涨缩信息 var scale = get_scale_info({layers:work_layers}); // -----涨缩值信息确认 par.scale = scale; workstep.forEach(function(step){ Step = step; GEN.openStep({job:job,name:step}); GEN.clearLayers(); GEN.affectedLayer( {mode:'all',affected:'no'} ); GEN.COM( "sel_options,clear_mode=clear_after,display_mode=all_layers,area_inout=inside,area_select=select,select_mode=standard,area_touching_mode=exclude"); GEN.units( {type:par.units} ); GEN.zoomHome(); PAR.profile_limits = GEN.getProfileLimits({job:job,step:step,units:'mm'}); PAR.profile_limits.xsize = Number(PAR.profile_limits.xsize); PAR.profile_limits.ysize = Number(PAR.profile_limits.ysize); PAR.profile_limits.xmin = Number(PAR.profile_limits.xmin); PAR.profile_limits.ymin = Number(PAR.profile_limits.ymin); PAR.profile_limits.xmax = Number(PAR.profile_limits.xmax); PAR.profile_limits.ymax = Number(PAR.profile_limits.ymax); PAR.profile_limits.xc = PAR.profile_limits.xsize/2-Math.abs(PAR.profile_limits.xmin); PAR.profile_limits.yc = PAR.profile_limits.ysize/2-Math.abs(PAR.profile_limits.ymin); PAR.sr = GEN.getSRLimits({job:job,step:step,units:'mm'}); work_layers.forEach(function(layer){ //钻孔输出 var output_layer = job+'-'+layer+'-ori'; // Job.'-'.$layer.'-ori' drill_out({layer:layer,output_layer:output_layer,scale_x:PAR.scale[layer].x,scale_y:PAR.scale[layer].y}); //钻孔程式编辑 var new_layer=''; if(PAR.scale[layer].x != 1 || PAR.scale[layer].y != 1){ new_layer= new_name+'.'+layer+'X'+PAR.scale[layer]+'Y'+PAR.scale[layer].y }else{ new_layer= new_name+'.'+layer; } var new_file = PAR.out_dir+'/'+new_layer; // 分割文件内容 edit_nc_file({layer:layer,output_file:PAR.out_dir+'/'+output_layer,new_file:new_file,x:PAR.scale[layer].x,y:PAR.scale[layer].y});//drl_type:$drl_type //删除钻孔输出的临时文件 // fs.unlink(PAR.out_dir+'/'+output_layer); //回读钻孔程式 if( PAR.reread_layer =~ /yes/i){ var new_layer_2 = new_layer; input_drill_program({layer:layer,file:PAR.out_dir+'/'+new_layer_2,new_layer:new_layer});//drl_type:drl_type,drl_side=>$drl_side } }) }) // 保存 if(/yes/ig.test(par.auto_save)){GEN.checkInout({job:job,mode:"out"}); GEN.saveJob({ job: job });GEN.checkInout({job:job,mode:"in"});GEN.closeJob({job:job});} else {GEN.checkInout({job:job,mode:"in"})} if (mode === "aimdfm") { $.QDfm.updateRow({table: "pdm_aimdfm_task",data: {progress: 33.33},where: { id: $.task_id }}); if (GEN.hasError()) { Status = 'error';resultData.push({ type: "error", title: "GEN错误!", detail: [{ desc: _.join(GEN.STATUS, "\n") }] }); return {status: Status,result_data: resultData}; } else { resultData.push({ type: "info", title: "操作完成, 请注意检查!" }); return {status: Status,result_data: resultData}; } }else { return "Done" } } catch (e) { IKM.msg(_.join(GEN.STATUS, "\n"));IKM.msg(e);Status = 'error'; resultData.push({type: "error", title: "脚本执行出错!", detail: [{desc: _.toString(e)}]}); return (mode === "aimdfm") ? {status: Status, result_data: resultData} : "Error"; } function NewGUI (gui) { this.msgBox = function(props){ // title type content button props = props || {} return gui.msgBox(props.title || "title",props.type || "info",props.content || "content",props.button || ["ok", "cancel"]); } this.selectFromTreeview = gui.selectFromTreeview this.selectFile = function(props){ // "choose something", "*", true, "file", "/home/abby/fast_io" props = props || {} return gui.selectFile(props.title || "choose something",props.filter || "*",props.multiple || false, "file",""); } this.selectSingle = function(props) { props = props || {} return gui.selectSingle({ "title": props.title || "select", "list": props.list || [], "default": props["default"] || "", "columns": props.columns || 2, "gen":props.gen || GEN }); } this.selectMultiple = function(props) { props = props || {} return gui.selectMultiple({ "title": props.title || "select", "list": props.list || [], "defaultvalue": props["defaultvalue"] || [""], "defaultsize": props["defaultsize"] || [200, 100], "columns": props.columns || 2, "gen":props.gen || GEN }); } this.selectFromTable = gui.selectFromTable this.snapScreen = gui.snapScreen this.imageViewer = gui.imageViewer this.inputBox = gui.inputBox this.showForm = gui.showForm this.lockUnlockLayer = function(props){ props = props || {} var tmp = {} if (props.matrix) { for (var key in props.matrix) { var item = props.matrix[key] tmp[key] = { row : item.row, name : item.name } } } return gui.lockUnlockLayer({ title: props.title || "lockUnlockLayer", layermatrix:props.layermatrix || tmp }) } this.passwordBox = function(props){ props = props || {} return gui.passwordBox({title:props.title || "password", password:props.password || "1212"}) } this.selectJobLayer = function (props) { props = props || {} return gui.selectJobLayer({ layertypelist: props.layertypelist || [ {name: "all", display_name: "all", filter: function(x) { return x }}, {name: "signal", display_name: "signal", filter: function(x) { return x["layer_type"] === "signal"; }}, {name: "power_ground", display_name: "power_ground", filter: function(x) { return x["layer_type"] === "power_ground"; }}, {name: "mixed", display_name: "mixed", filter: function(x) { return x["layer_type"] === "mixed"; }}, {name: "solder_mask", display_name: "solder_mask", filter: function(x) { return x["layer_type"] === "solder_mask"; }}, {name: "silk_screen", display_name: "silk_screen", filter: function(x) { return x["layer_type"] === "silk_screen"; }}, {name: "solder_paste", display_name: "solder_paste", filter: function(x) { return x["layer_type"] === "solder_paste"; }}, {name: "drill", display_name: "drill", filter: function(x) { return x["layer_type"] === "drill"; }}, {name: "rout", display_name: "rout", filter: function(x) { return x["layer_type"] === "rout"; }}, {name: "document", display_name: "document", filter: function(x) { return x["layer_type"] === "document"; }} ], //defaultlayertype: "ha", joblist: props.joblist || [], defaultJob: props.defaultJob || [], // select by default steplist: props.steplist || [], // defaultstep: "step3", showstep: props.showstep || true, selectmode: props.selectmode || "multiple", // single/multiple layermatrix: props.layermatrix || { }, defaultlayer: props.defaultlayer || [] }) } } function getLayer(props){ if(!props){return} if(!props.context){props.context = "board"} var matrix = GEN.getMatrix({job:job}) return Object.keys(matrix).reduce(function(a,b){ var info = matrix[b]; var ret = true; for (var key in props) { if(!Array.isArray(props[key])){props[key] = [props[key]]} if(info[key] && props[key].indexOf(info[key]) < 0){ ret = false } } if(ret){ a.push(props.res == "info"? info : b) } return a },[]) } function _deleteLayer(layers){ layers = Array.isArray(layers.layer) ? layers.layer : [layers.layer]; layers.forEach(function(layer){ if(GEN.isLayerExists({job:Job,layer:layer})){ GEN.deleteLayer({job:Job,layer:[layer]}) } }) } function getWorkStep(props){ var steplists = GEN.getStepList({job:job}); if(steplists.length == 0){return "该料号没有step"} var steps_tmp = steplists.filter(function(name){ var reg = new RegExp(par.step_filter, "ig") return reg.test(name) }) if(steplists.length == 0){return "根据脚本参数过滤出来的step不存在,请检查资料或者脚本参数配置!"} var workstep = gui.selectMultiple({ title: "请先择工作step", size:[200,100], defaultsize:[200,100], list: steplists.map(function(v){ var tmp = {}; tmp[v] = v ;return tmp}), defaultvalue: steps_tmp, columns: 1, gen: GEN }) if(workstep.length == 0 ) {return "没有先择step"} return workstep } function select_work_layer(par) { var drill = []; var matrix = GEN.getMatrix({job:Job}); Object.keys(matrix).forEach(function(layer){ if (!/ddr/.test(layer)){ if(matrix[layer].layer_type == "drill"){ drill.push(layer) } } }) if(drill.length == 0){ IKM.msg("资料中未找到钻孔层") } if (PAR.is_select_lyr == 'yes' && drill.length > 1) { var tmp_matrix={}; drill.forEach(function(v){ tmp_matrix[v] = matrix[v] }) drill = GUI.selectLayer({ title:'请选择输出层别', layermatrix:tmp_matrix, selectmode : 'multiple'}); // single } return drill; } function get_scale_info(par){ var rows={},n=0; par.layers.forEach(function(layer){ n++; if(!rows[layer]){rows[layer] = {}} rows[layer].sequence = n; rows[layer].layer = layer; if(layer == "md"){ rows[layer].x = 1.0004; rows[layer].y = 1.0004; } else{ rows[layer].x = 1.0000; rows[layer].y = 1.0000; } }) return rows; } function drill_out(par){ var nc_set = par.layer; var ncsets = GEN.getNcsetsList({job:Job,step:Step,layer:par.layer}); if( ncsets.length ){ if (ncsets.filter(function(v){return /^($nc_set)$/.test(v)}).length > 0) { GEN.COM('ncset_delete',{name:nc_set}); } } //钻带涨缩中心点 var anchor_x = (par.scale_x != 1 || par.scale_y != 1) ? PAR.profile_limits.xc : 0; var anchor_y = (par.scale_x != 1 || par.scale_y != 1) ? PAR.profile_limits.yc : 0; if(fs.exists(PAR.out_dir+"/"+par.output_layer)){ fs.unlink(PAR.out_dir+"/"+par.output_layer) } var org_x=0,org_y=0,angle; // if(PAR.profile_limits.ysize == 603 && PAR.profile_limits.xsize == 706){ // org_x = PAR.profile_limits.yc;//- 15 // org_y = 5; // angle = 270; // }else if(PAR.profile_limits.ysize == 603 && PAR.profile_limits.xsize == 606){ // org_x = PAR.profile_limits.xc;//- 5 // org_y = 5; // angle = 0; // }else{ // org_x = PAR.profile_limits.xc;//- 24 // org_y = 5; // angle = 0; // } // 导出 GEN.COM("ncset_cur,job="+Job+",step="+Step+",layer="+par.layer+",ncset="+nc_set); GEN.COM("ncd_set_machine,machine=excellon2,thickness=0");//excellon2 cpc_pn basic_excellon GEN.COM("ncd_register,angle=0,mirror=no,xoff=0,yoff=0,version=1,xorigin="+org_x+ ",yorigin="+org_y+",xscale="+par.scale_x+",yscale="+par.scale_y+ ",xscale_o="+anchor_x+",yscale_o="+anchor_y); GEN.COM("ncd_cre_drill"); GEN.COM("ncd_ncf_export,stage=1,split=1,dir="+PAR.out_dir+",name="+par.output_layer); GEN.COM("ncset_delete,name="+par.layer); } // 整理输出文件数据 function edit_nc_file(par){ // { // "layer": "drl", // "output_file": "C:/Users/Administrator/Desktop/jobs/demo/new_test/demo-drl-ori", // "new_file": "C:/Users/Administrator/Desktop/jobs/demo/new_test/new_test.drl", // "x": 1, // "y": 1 // } // 读取文件内容 var fileCtx = fs.readFile(par.output_file) // 分割文件内容 var data = split_program(fileCtx); // 排序 convert_new_program(data); // 重写 write_new_file({new_file:par.new_file, data:data}) } // 分割文件内容 function split_program(string){ var data = string.split("\n"); var info = {overhead:[],head:[],neck:[],body:[],end:[]}; var flag="start",router_flag; data.forEach(function(line){ if( flag == 'start' ){ if( line == 'M48' ){ flag = 'overhead'; } } else if( flag == 'overhead' ){ if( /^T01C/i.test(line) ){ flag = 'head'; } } else if( flag == 'head' ){ if( !/^T\d+/i.test(line) ){ flag = 'neck'; } } else if( flag == 'neck' ){ if( /^T01/i.test(line) ){ flag = 'body'; } } else if( flag == 'body' ){ if( /^M30$/i.test(line) ){ flag = 'end'; } } if( flag == 'overhead' ){ info.overhead.push(line) } else if( flag == 'head' ){ info.head.push(line) } else if( flag == 'neck' ){ info.neck.push(line) } else if( flag == 'body' ){ if(/^(T(\d+))$/i.test(line) ){ router_flag = RegExp.$1; } if(router_flag){ if(!/^T\d/.test(line)){ var tmpT = info.body.filter(function(v){ return v.name == router_flag }) if(tmpT.length > 0){ tmpT[0].value.push(line) } else { info.body.push({ name: router_flag, value: [line] }) } } //判断孔的范围 2020-04-21 // if($num - $section_number < 0.001 and line !~ /^T/){ // my $point = change_coode_to_vale(line); // my $are_check = 0; // foreach my $symbol (@drl_section_data){ // my $dist = TL::GenMath->point2sym_dist($point,$symbol); // if($dist == 0){ // $are_check = 1; // last; // } // } // if($are_check){ // push @drl_section,line; // }else{ // push @{$info{body}{$router_flag}{value}},line; // } // }else{ // info.body[router_flag].value.push(line) // } } } else if( flag == 'end' ){ info.end.push(line) } }) return info } function convert_new_program(info){ // 这里只对head和body排序 var head = info.head; var body = info.body; // 做一个临时排序基准数组 var head_tmp = head.map(function(v) { var tmp = v.split(/c/ig) return { name:tmp[0], value : parseFloat(tmp[1]) } }) head_tmp.sort(function(a,b){ var a_tmp_value = (a.value==2.1 || a.value==0.7) ? -a.value : a.value; var b_tmp_value = (b.value==2.1 || b.value==0.7) ? -b.value : b.value; if(/\.\d\d1$/.test(a_tmp_value)){ a_tmp_value = a_tmp_value + 10000; } if(/\.\d\d1$/.test(b_tmp_value)){ b_tmp_value = b_tmp_value + 10000; } if(/\.\d\d2$/.test(a_tmp_value)){ a_tmp_value = a_tmp_value + 20000; } if(/\.\d\d2$/.test(b_tmp_value)){ b_tmp_value = b_tmp_value + 20000; } return a_tmp_value - b_tmp_value; }) head_tmp = head_tmp.map(function(v){return v.name}) // head body 根据基准排序 head.sort(function(a,b){ var aT = /^(T\d+)C/.exec(a)[1]; var bT = /^(T\d+)C/.exec(b)[1]; return head_tmp.indexOf(aT) - head_tmp.indexOf(bT) }) body.sort(function(a,b){ var aT = a.name; var bT = b.name; return head_tmp.indexOf(aT) - head_tmp.indexOf(bT) }) // 重写head与body head = head.map(function(v, i){ var Tnum = /^T(\d+)C/.exec(v)[1] - 0; if(Tnum != (i+1)){ var newT = "T" + ((i+1)>9? (i+1) : "0"+(i+1)) v = v.replace(/^T\d+/, newT) } return v }) body = body.map(function(v, i){ var Tnum = /^T(\d+)/.exec(v.name)[1] - 0; if(Tnum != (i+1)){ var newT = "T" + ((i+1)>9? (i+1) : "0"+(i+1)) v.name = newT } return v }) info.head = head; info.body = body; } function write_new_file(par){ // {new_file:new_file, data:data} var data = par.data var newstr = ""; var overhead = data.overhead.join("\n"); var neck = data.neck.join("\n"); var head = data.head.join("\n"); newstr += overhead + "\n" + head + "\n" + neck + "\n"; var body = ""; data.body.forEach(function(v){ body += v.name + "\n"; body += v.value.join("\n") + "\n" }) newstr += body; var end = data.end.join("\n"); newstr += end; fs.writeFile(par.new_file, newstr) } function input_drill_program(par){ GEN.COM( "input_manual_reset"); GEN.COM( "input_manual_set,path="+par.file+",job="+Job+",step="+Step +",format=Excellon2,data_type=ascii,units=mm,coordinates=absolute," +"zeroes=none,nf1=3,nf2=3,decimal=no,separator=nl,tool_units=mm,layer="+par.new_layer +",wheel=,wheel_template=,nf_comp=0,multiplier=1,text_line_width=0.0024," +"signed_coords=no,break_sr=yes,drill_only=no,merge_by_rule=no,threshold=200,resolution=3"); GEN.COM( "input_manual,script_path="); GEN.zoomHome(); }