/* NAME: DESCRIPTION: 客户数据分析 PARAMETER: [ { name : 'pcs_step', title : 'pcsStep名', type : 'LineEdit', property : {tool_tip : 'pcs step名,默认是cad'} }, { name : 'array_step', title : 'arrayStep名', type : 'LineEdit', property : {tool_tip : 'array step名,默认是stp'} }, { name : 'erf', title : 'erf名称', type : 'LineEdit', property : {tool_tip : 'erf名称'} }, { name : 'auto_save', title : '自动保存', type : 'RadioBox', property : { item_list:[ {name:'yes',text:'YES'}, {name:'no',text:'NO'}, ], tool_tip:'是否自动保存料号开关' } } ] VERSION_HISTORY: V1.00 2020 3-30 Scott HELP:

功能简介

客户数据分析


参数配置

客户参数

注意事项

● 无


*/ // 引入模块 包 var $ = require('topcam.scriptfunc').argv(); var fs = require('fs'); var _ = require('lodash'); var JobId = $.job_id; var database = require("topsin.database"); var Omatrix = {}; database.addConnection($.conf.database_conf, "DFM"); var QDfm = database.query("DFM"); if ($.conf.product_type == "aimdfm") { QDfm.updateRow({ table: "pdm_aimdfm_task", data: { current_process_title: $.process_title }, where: { id: $.task_id } }); } var GEN = $.gen; var Job = $.job_name; var db = $.db; var Status = 'ok'; var resultData = []; var PAR = {}; if ($.hasOwnProperty('script_parameter')){ PAR = JSON.parse($.script_parameter); } try { console.log("=============================================>anaysis_start"); var par = PAR; if(par.erf == ""){delete PAR.erf} // if(par.erf == ""){par.erf = "GBM_0.50z"} if(_.isEmpty(Job)) throw "没有传入料号名!"; var job = Job.toLowerCase(); if(!GEN.isJobExists({job:job})){ throw "job "+ job+ " is not exist" } // 检查料号是否能够check out if(GEN.checkInout({job:job,mode:"test"}) != 0){ throw "the job check" } GEN.checkInout({job:job,mode:"out"}); var pcs_step = par.pcs_step == "" ? "cad" : par.pcs_step; var array_step = par.array_step == "" ? "stp" : par.array_step; var step_list = GEN.getStepList({job:job}) if(step_list.indexOf(array_step)<0){ array_step = false } if(step_list.indexOf(pcs_step)<0){ pcs_step = step_list[0] } var matrix = UPLOAD_LAYER_MATRIX({job:job}) // 分析matrix 获得分析后的matrix信息 GEN.openStep({job:job, name:pcs_step}) GEN.units({type:"mm"}) _.values(matrix).forEach(function(v){ if(v.context == "board" && v.layer_type == "drill"){ if(v.type == "laser_drill"){ GEN.affectedLayer({affected:'no',mode:'all'}) GEN.workLayer({name:v.name,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selAllFeat() if(GEN.getSelectCount()>0){ GEN.COM("cur_atr_set,attribute=.drill,option=via") GEN.COM("sel_change_atr,mode=add") } GEN.clearLayers() GEN.selClearFeature() } else if(v.type == "main_drill" || v.type == "blind_drill" || v.type == "bury_drill") { GEN.affectedLayer({affected:'no',mode:'all'}) GEN.workLayer({name:v.name,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:v.drl_start,use:'filter',mode:'touch',f_types:"pad"}) GEN.selRefFeat({layers:v.drl_end,use:'filter',mode:'touch',f_types:"pad"}) if(GEN.getSelectCount()>0){ GEN.COM("cur_atr_set,attribute=.drill,option=plated") GEN.COM("sel_change_atr,mode=add") } GEN.selReverse() if(GEN.getSelectCount() > 0){ GEN.COM("cur_atr_set,attribute=.drill,option=non_plated") GEN.COM("sel_change_atr,mode=add") } } } }) GEN.closeStep() console.log("===================>steplist:"+_.toString(step_list)) if(step_list.indexOf(pcs_step)<0){throw "can not find pcsstep"} if(step_list.indexOf(array_step)<0){array_step = false} console.log("=============== ====================> 1matrix") var analysis_obj = analysis({job:job,jobId:JobId,pcs_step:pcs_step,array_step:array_step,matrix:matrix}) // 创建profile var tmp_matrix = GEN.getMatrix({job:job}) var board_layer = Object.keys(tmp_matrix).filter(function(v){ return tmp_matrix[v].context == "board" }) GEN.openStep({job:job, name:pcs_step}) var now_profile = GEN.getProfile({job:job, step:pcs_step}) console.log("profile:===============>"+now_profile); console.log(now_profile.match(/\n/ig).length); if(now_profile.match(/\n/ig).length == 1){ // 如果没有profile createOutline({job:job, step:pcs_step, matrix: tmp_matrix}) } else { GEN.affectedLayer({affected:'yes',layer: board_layer, clear_before:"yes"}) GEN.selectByFilter({profile:"out"}) if(GEN.getSelectCount() > 0){ GEN.selDelete() } } GEN.closeStep() var config = { jobInfo: { layer_count: ["signal","power_ground"], // Board属性的signal或者power_ground层 vc_card_size_w: {api:"vc_card_size", props:"xsize"}, // card短边尺寸 // ? 保留小数 vc_card_size_l: {api:"vc_card_size", props:"ysize"}, // card长边尺寸 // ? 保留小数 vc_array_size_w: {api:"vc_array_size", props:"xsize"}, // ! array短边尺寸 需要arr_step // ? 保留小数 vc_array_size_l: {api:"vc_array_size", props:"ysize"}, // ! array长边尺寸 需要arr_step // ? 保留小数 vc_pcs_count_on_panel: true, // todo array中pcs的数量 ! 需要arr_step stack_vias_number: true, // via孔连续叠加的层数 stack_vias_more: {only_value:true}, // yes|no : 14层板以上时,Stack Vias >=12时,存yes // ! 需要分析完via连续叠加层数 depth_drilling: {api:"layer_exist", props:"depth_drill"}, // yes|no :存在depth_drill 层时 ,存yes depth_routing: {api:"layer_exist", props:"depth_routing"}, // tmp yes|no :存在depth_routing 层时,,存yes laser_via_on_buried_hole: true, // todo via孔在埋孔上时,存yes milling_bit_size: true, // todo 检查array中pcs的最小间距值 milling_length: true, // todo 检查array中铣切长度 vc_src_01005_pad_result: {api:"board_has_attr", props:"01005_pad"}, // * yes|no:board 层中检查存在01005属性物件时,存yes 这里先拿.smd代替了 ATS_technology_25dc: {api:"layer_exist", props:"cavity"}, // yes|no:存在cavity层别时存yes ATS_technology_25dr: {api:"layer_exist", props:"cavity"}, // yes|no:存在cavity层别时存yes vc_src_EDGE_PLATING: true, // yes|no:检查线路外形是否存在物件,存在则存yes // !料号需要有rout层 edge_plating_length: true, // todo 检查线路外形处物件的长度 glod_finger: true, // todo yes|no:暂无逻辑 glod_finger_area: true, // todo 暂无逻辑 solder_mask_side: true, // top|bot|both:检查防焊层所在面次 solder_mask_side silk_screen_side: true, // top|bot|both:检查文字层所在面次 min_drl_size: true, // todo 0.5mm 最小圆孔 max_pth_drl_size: true, // todo 3.5mm 最大pth圆孔 max_npth_drl_size: true, // todo 6.0mm 最大npth圆孔 min_slot_drl_size: true, // todo 0.8mm 最小槽孔 max_slot_drl_size: true, // todo 1.2mm 最大槽孔 max_slot_drl_length: true, // todo 2.0mm 最大槽孔 max_spec_slot_drl_size: true, // todo 2.1mm 最大异形槽孔 max_spec_slot_drl_length: true, // todo 3.0mm 最大异形槽孔 } } console.log("===============================> 2analysis_obj") // 分析料号info var jobInfo = {} Object.keys(config.jobInfo).forEach(function(key){ var props = config.jobInfo[key]; console.log("===================================> 2analysis_obj:key:"+key) if(props){ try { if(props.hasOwnProperty("api") && props.hasOwnProperty("props")){ jobInfo[key] = analysis_obj["analysis_"+props.api](props.props) } else if(props.only_value){ jobInfo[key] = analysis_obj.jobInfo[key] } else { jobInfo[key] = analysis_obj["analysis_"+key](props) } } catch (e) { console.log(e); jobInfo[key] = "_error" } } }) console.log("===================================> 3 jobinfo") // 过滤掉料号信息的 _todo 和 _error for (var key in jobInfo) { if(jobInfo[key]==="yes"){jobInfo[key] = "Yes"} if(jobInfo[key]==="no"){jobInfo[key] = "No"} if(jobInfo[key] === "_todo" || jobInfo[key] === "_error"){ delete jobInfo[key] } } console.log("===================================> 4 save job info") save_job_info({ jobid: JobId, jobinfohash: jobInfo }) console.log("===================================> 5 save drill info") // 获取pcs_step 和 array_step的钻孔信息 var drill_info = {}; var drillLayers = analysis_obj.matrixInfo.mDrills; [pcs_step, array_step].forEach(function(step){ if(step){ var tmp_step = step + "_tmp" GEN.matrixCopyStep({job:job,step:tmp_step,step:tmp_step}) GEN.COM("copy_entity",{type:"step",source_job:job,source_name:step,dest_job:job,dest_name:tmp_step}) GEN.openStep({job:job, name: tmp_step}) GEN.COM('sredit_reduce_nesting,mode=one_highest') drill_info[step] = drill_info[step] || {}; drillLayers.forEach(function(layer){ var layer_tool_manager = GEN.getTool({job:job, step:step,layer:layer.name}) drill_info[step][layer.name] = layer_tool_manager }) GEN.closeStep() GEN.deleteStep({job:job,step:tmp_step}) } }) var pcs_tool_manager = drill_info[pcs_step]; var array_tool_manager = drill_info[array_step]; Object.keys(pcs_tool_manager).forEach(function(layer){ Object.keys(pcs_tool_manager[layer]).forEach(function(key){ var tool = pcs_tool_manager[layer][key]; var array_count; if(array_tool_manager && array_tool_manager[layer] && array_tool_manager[layer][key]){array_count = array_tool_manager[layer][key].count} var data = { job_id: JobId, layer_name: layer, tool_num: key, tool_flag: key, tool_type: tool.shape, drill_type:tool.type, drill_size : tool.drill_size, drill_slot_length: tool.slot_len, finish_size : tool.finish_size, finish_slot_length: tool.slot_len, size_tol_lower: tool.min_tol, size_tol_upper: tool.max_tol, pcs_count: tool.count, array_count: array_count, // todo attr_data: {} // {"allowance": 2, "org_layer_name": "hhhh"} } if(!array_count){delete data.array_count} var id = db.query("",function(q){ return q.selectValue({ table:'pdm_job_cam_drill', field:"id", where:{job_id:JobId, layer_name: layer,tool_num: key} }) }); console.log("=========>drillid:"+id) if(/done/ig.test(id) || !id){ db.query("",function(q){ return q.insertRow({ table:'pdm_job_cam_drill', data:data, return_field:'id', }) }); }else{ db.query("",function(q){ return q.updateRow({ table:'pdm_job_cam_drill', where: {id:id}, data:data, update_policy:{tags:'array_append', attr_data:'json_merge'} }) }); } }) }) console.log("=============================> 6 set smd bga") var allStep = GEN.getStepList({job:job}) allStep.forEach(function(step){ GEN.openStep({job:job,name:step}) console.log(3) GEN.COM("chklist_single,show=yes,action=valor_cleanup_set_smd") console.log(4) GEN.COM("chklist_cupd,chklist=valor_cleanup_set_smd,nact=1,params=((pp_layer=.type=signal|mixed&side=top|bottom)(pp_work_on=SMD\;BGA)(pp_delete=No)(pp_types=Square\;Rect\;Oval)(pp_other_smd=)(pp_sm=No)(pp_drill=)(pp_rotate=No)(pp_ignore_covered=Yes)(pp_bga_types=Round)(pp_other_bga=)(pp_sm_bga=No)(pp_bga_max_pitch=70)(pp_bga_actions=Set attribute)(pp_bga_suffix=_bga)(pp_identify_gf=)),mode=regular") console.log(5) GEN.COM("get_user_name") console.log(6) GEN.COM("get_job_path,job="+job) console.log(7) GEN.COM("disp_on") console.log(8) GEN.COM("origin_on") console.log(9) GEN.COM("chklist_cnf_act,chklist=valor_cleanup_set_smd,nact=1,cnf=no") console.log(10) GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile") console.log(11) GEN.COM("skip_next_pre_hook") console.log(12) GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile") console.log(13) GEN.COM("get_user_name") console.log(14) GEN.COM("skip_current_command") console.log(15) GEN.COM("disp_on") console.log(16) GEN.COM("origin_on") console.log(17) GEN.COM("show_tab,tab=Checklists,show=no") GEN.closeStep() }) // GEN.createChklist() console.log("============= ===============> 6 analysis smd") // smd var smdInfo; try { if(!analysis_obj.matrixInfo.mOuters[0].solderL){throw "no mask"} smdInfo = smdAnalysis({job:job,steplist:[pcs_step],layers:analysis_obj.matrixInfo.mOuters,attr:".smd"}) } catch (msg) { console.log("smdInfo:error:"+msg) } // bga console.log("===================================> 7 bga info") var bgaInfo; // try { bgaInfo = bgaAnalysis({job:job,steplist:[pcs_step],layers:analysis_obj.matrixInfo.mOuters,attr:".bga"}) // } catch (msg) { // console.log("bgaInfo:error:"+msg) // } console.log("========================bgaInfo:" + _.toString(bgaInfo)); // 保存 console.log("============== =====================> 8 save bga smd info") var save_info = [smdInfo, analysis_obj.jobInfo.laser_info,bgaInfo]; // 保存 smd 和 bga数据 save_info.forEach(function(item){ if(JSON.stringify(item)!= "{}" && item){ Object.keys(item).forEach(function(key){ var val = item[key] save_layerinfo({ jobid: JobId, layer: key, layerinfohash: val }) }) } }) console.log("================================> 9 copper_percent signal drill") // 分析layer info var stepList = [pcs_step]; var oChecklistName = "mychecklist" var signalLayers = analysis_obj.matrixInfo.mSignals.map(function(v){return v.name}) var drillLayers = analysis_obj.matrixInfo.mDrills.map(function(v){return v.name}) var info = { min_line_width: ["line","user_nor_line"], min_line_spacing: ["l2l"], min_line2pad: ["p2line"], min_pad2pad: ["p2p", "smd2smd", "smd2pad"], min_ar: ["ar","pth_ar"] } save_job_info({ jobid: JobId, jobinfohash: {ATS_surface_area_base_on:"Card"} }) stepList.forEach(function(step){ GEN.openStep({ job: job, name: step }) // 曝光 analysis_obj.matrixInfo.mOuters.forEach(function(item){ if(item.solderL){ var tmp_info = GEN.exposedArea({layer1:item.signalL,mask1:item.solderL}) // {"area":"0.73817","percent":"8.986"} var tmp_area = tmp_info.area var tmp_percent = tmp_info.percent; var tmp_data = /top/ig.test(item.signalL) ? {carbon_Area_front:tmp_area} : {carbon_Area_back:tmp_area} save_job_info({ jobid: JobId, jobinfohash: tmp_data }) save_layerinfo({ jobid: JobId, layer: item.signalL, layerinfohash: { ref_layer: item.solderL, exposed_area: tmp_percent } }) } }) GEN.clearLayers() GEN.affectedLayer({ affected: 'no', mode: 'all' }) // 创建chklist并运行 如果chklist存在先删除 if (GEN.isChklistExists({ job: job, step: step, chklist: oChecklistName })) { GEN.COM("chklist_delete", { chklist: oChecklistName }) } var tmpitem = { name: "signal_layer_checks", nact: 1, action: "valor_analysis_signal", params: { pp_layer: ".affected", pp_spacing: 20, pp_selected: "All", pp_r2c: 10, pp_d2c: 15, pp_sliver: 8, pp_min_pad_overlap: 5, pp_check_missing_pads_for_drills: "Yes", pp_use_compensated_rout: "Skeleton", pp_sm_spacing: "Yes" } } if(par.erf){ tmpitem.erf = par.erf } createChklistAndRun({ // 创建checklist并运行 layers: signalLayers, items: [tmpitem] }) console.log("==================================> 11 signals analysis") // signal层分析结果 var res = analysisChkAttr({layers:signalLayers, info:info, step:step, job:job, oChecklistName:oChecklistName}) // 钻孔 var drillToSignals = drillLayers.map(function(v){ // 获取到钻孔层对应的顶层和底层 var simbols = GEN.getLayerSymsHist({job:job,step:step,layer:v}) var symbol = _.values(simbols).sort(function(a,b){return Number(a.size)-Number(b.size)}) .reduce(function(a,b){ if(b.pad!="0"){ a.push(b.symbol) } return a },[])[0] return {layer:v,symbol:symbol,start:matrix[v]["drl_start"],end:matrix[v]["drl_end"]} }) console.log("==================================> 12 Drill analysis") var drillRes = analysisDrill(drillToSignals,step) // 钻孔分析结果 console.log("================drillRes:" + _.toString(drillRes)); throw "tmp" // 数据入库 Object.keys(res).forEach(function(key){ var val = res[key] save_layerinfo({ jobid: JobId, layer: key, layerinfohash: val }) }) drillRes.forEach(function(item){ save_layerinfo({ jobid: JobId, layer: item.layer, layerinfohash: { drl_pad_top: item.drl_pad_top, drl_pad_bot: item.drl_pad_bot, } }) }) // 铜面积 console.log("=============================> 13 save copper_percent") var copper_percent_pcs = signalLayers.map(function(v){ var tmp = {layer:v} tmp.copper_percent = GEN.copperArea({layer1:v}).percent + "%" return tmp }) console.log("================ ==signalLayers============"+_.toString(signalLayers)); console.log(_.toString(copper_percent_pcs)); GEN.closeStep() copper_percent_pcs.forEach(function(item){ save_layerinfo({ jobid: JobId, layer: item.layer, layerinfohash: { copper_percent: item.copper_percent } }) }) }) // 保存 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"}) } 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 }; } } catch (e) { Status = 'error'; console.log("==================== ============>error"); console.log(_.toString(e)); resultData.push({type: "error", title: "脚本执行出错!", detail: [{desc: _.toString(e)}]}); return {status: Status, result_data: resultData}; } function UPLOAD_LAYER_MATRIX(props){ var job = props.job props.jobcategory = props.jobcategory || "work" var matrix = ANALYSIS_STACKUP({job:job, jobcategory:props.jobcategory}); var layers = Object.keys(matrix).sort(function(a,b){return matrix[a]["row"] - matrix[b]["row"]}) var tableName = "pdm_job_" + props.jobcategory + "_layer"; console.log("===========>matrix upload"); var oLayers = db.query("",function(q){ return q.selectMapMap({ table:tableName, field: ["odb_name", "release_status"], where:{job_id:JobId}, uniquefield: "odb_name" }) }); db.query("",function(q){ return q.deleteRow({ table:tableName, where:{job_id:JobId}, }) }); var fieldLst = ["name", "odb_context", "odb_type", "odb_polarity", "odb_side", "drl_start", "drl_end", "row_num", "type", "drl_start_num", "drl_end_num", "drl_from_num", "drl_to_num", "drl_connect_to", "odb_name", "side", "stackup_num", "customer_field", "input_file_name", "odb_row_num" ]; layers.forEach(function(layer){ var layerInfo = matrix[layer]; var tmpData = { "job_id": JobId, "name": layerInfo["name"] }; tmpData["release_status"] = (oLayers&&oLayers.hasOwnProperty(layerInfo["odb_name"])) ? oLayers[layerInfo["odb_name"]]["release_status"] : null; for (n = 0; n < fieldLst.length; n++) { tmpData[fieldLst[n]] = layerInfo[fieldLst[n]]; } db.query("",function(q){ return q.insertRow({ table:tableName, data: tmpData }) }); }) console.log("===========>matrix upload end"); return matrix } function ANALYSIS_STACKUP(props){ var job = props.job if(!props.hasOwnProperty("jobcategory")){ props.jobcategory = 'work' } var matrix = GEN.getMatrix({job:job}) var layer_count = GEN.getLayerCount({job:job}) // ! save_job_info({jobid:JobId,jobcategory:props.jobcategory,jobinfohash:{TL_layer_count:layer_count}}); _.values(matrix).sort(function(a,b){return a.row-b.row}).forEach(function(layer){ layer.odb_name = layer.name; layer.name = layer.tl_name; layer.odb_context = layer.context; layer.odb_type = layer.layer_type; layer.odb_polarity = layer.polarity; layer.odb_side = layer.side; layer.row_num = layer.tl_num; layer.type = layer.tl_type; layer.side = layer.enum_tl_side; layer.input_file_name = layer.file_name; layer.odb_row_num = layer.row; if (layer.odb_name == 'drill'){ layer.name = 'drill'; layer.drl_start_num = 1; layer.drl_end_num = layer_count; layer.drl_from_num = 1; layer.drl_to_num = layer_count; layer.type = 'main_drill'; } else if (/^d(\d+)\-(\d+)$/.test(layer.odb_name)){ var tmp = /^d(\d+)\-(\d+)$/.exec(layer.odb_name) var drl_star = tmp[1]; var drl_end = tmp[2]; layer.name = 'd' + drl_star + '-' + drl_end; layer.drl_start_num = drl_star; layer.drl_end_num = drl_end; layer.drl_from_num = drl_star; layer.drl_to_num = drl_end; if(drl_end - drl_star == 1){ layer.type = 'laser_drill'; // 镭射 } else if( drl_star == 1 || drl_end == layer_count ){ layer.type = 'blind_drill'; // 埋孔 } else{ layer.type = 'bury_drill'; // 盲孔 } } else if (/\-a$/.test(layer.odb_name)){ layer.side = 'top'; if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } else if (/\-b$/.test(layer.odb_name)){ layer.side = 'bottom'; if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } else{ if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } }) return matrix; } function getMatrixInfo(props){ // 获取matrix各种信息 var job = props.job var matrix = GEN.getMatrix({job:job}) Omatrix = matrix; var res = { matrix: matrix, // matrix matrixVal: [], // matrix 的 value数组 mSignal: {}, // board的signal层 {} mSignals: [], // board的signal层 [] mDrill: {}, // board的drill层 mDrills: [], // board的drill层 mSolderMask: {}, // 防焊层 mSolderMasks: [], // 防焊层 mOuters: [], // 外层和对于的防旱 mBoardLayer: [] // board层 } for (var key in matrix) { var value = matrix[key] res.matrixVal.push(value) if(value.context == "board"){ res.mBoardLayer.push(key) switch (value.layer_type) { case "signal": res.mSignal[key] = value res.mSignals.push(value) break; case "drill": res.mDrill[key] = value res.mDrills.push(value) break; case "solder_mask": res.mSolderMask[key] = value res.mSolderMasks.push(value) break; } } } res.matrixVal = res.matrixVal.sort(function(a,b){return Number(a.row) - Number(b.row)}) res.mSignals = res.mSignals.sort(function(a,b){return Number(a.row) - Number(b.row)}) res.mDrills = res.mDrills.sort(function(a,b){return Number(a.row) - Number(b.row)}) // 找出外层 以及外层对应的防焊层 [{signalL:"top", solderL:"smt"}] res.mOuters = res.mSignals.reduce(function(a,b){ if(b.tl_type == "outer"){ var solderLayers = res.mSolderMasks.filter(function(v){ return v.side == b.side }) a.push({ signalL: b.name, solderL: solderLayers.length >0 ? solderLayers[0]["name"] : null }) } return a },[]) return res } function selCopyLayer(props){ // 拷贝选择的到辅助层 var layer = props.layer var job = props.job if(GEN.isLayerExists({job:job,layer:layer})){ GEN.deleteLayer({job:job,layer:layer}) } GEN.selCopyOther({dest:'layer_name',target_layer:layer}) } function save_job_info(props){ // 保存料号信息 var jobid = props.jobid; var jobinfohash = props.jobinfohash; Object.keys(jobinfohash).forEach(function(key){ var val = jobinfohash[key]; var value = db.query("",function(q){ return q.selectValue({ table:'pdm_job_jobattr', field:"value", where:{job_id:jobid, attr_name: key} }) }); console.log("jobid:"+jobid+"==========dbjobvalue:" + val) if(/done/ig.test(value) || !value){ db.query("",function(q){ return q.insertRow({ table:'pdm_job_jobattr', // todo data:{job_id:jobid, attr_name:key, value:val}, // todo return_field:'job_id', }) }); } else if (value != val) { console.log("jobid:"+jobid+"==========update jobvalue:"+value+"->" + val) db.query("",function(q){ return q.updateRow({ table:'pdm_job_jobattr', where:{job_id:jobid, attr_name: key}, data:{value:val}, }) }); } }) } function save_layerinfo(props){ // 保存层信息 var jobid = props.jobid; var layer = props.layer; if(Omatrix[layer] && Omatrix[layer].tl_name){ if(!(/^drill/ig.test(Omatrix[layer].tl_name))){ layer = Omatrix[layer].tl_name } } var layerinfohash = props.layerinfohash; Object.keys(layerinfohash).forEach(function(key){ var val = layerinfohash[key]; var value = db.query("",function(q){ return q.selectValue({ table:'pdm_job_layerattr', field:"value", where:{job_id:jobid, attr_name: key, layer:layer} }) }); console.log("+==========dblayervalue:" + value) if(/done/ig.test(value) || !value){ db.query("",function(q){ console.log("+==========insertRowlayervalue:layer:"+layer+";attrname:"+key+";value:"+ val) return q.insertRow({ table:'pdm_job_layerattr', // todo data:{job_id:jobid, attr_name:key, value:val, layer:layer}, // todo return_field:'job_id', }) }); } else if (value !== val) { db.query("",function(q){ console.log("+==========updateRowlayer:layer:"+layer+";attrname:"+key+";value:"+ val) return q.updateRow({ table:'pdm_job_layerattr', where:{job_id:jobid, attr_name: key}, data:{value:val}, }) }); } }) } function analysis(props){ var job = props.job || Job; var jobId = props.jobId || JobId; var pcs_step = props.pcs_step || false; var array_step = props.array_step || false; var matrix = props.matrix; function T_m_p(props){ this.job = props.job; this.jobInfo = {}; this.jobId = props.jobId; if(props.pcs_step){ this.pcs_step = props.pcs_step; } if(props.matrix){ this.matrix = props.matrix; } if(props.array_step){ this.array_step = props.array_step; } this.matrixInfo = getMatrixInfo({job:this.job}) this.init(); } T_m_p.prototype.init = function(){ var init_checking = ["job", "jobId", "pcs_step", "matrix"]; var t = this; init_checking.forEach(function(v){ if(!t[v]){t.e(v+" is undefined")} }) } T_m_p.prototype.e = function(e){ // 处理error console.log(e) throw e } T_m_p.prototype.analysis_layer_count = function(props){ // 分析board属性的层数量 []string var matrix = this.matrixInfo.matrixVal; var res = matrix.filter(function(v){return v.context == "board" && props.indexOf(v.layer_type) >= 0 }) return res.length } T_m_p.prototype.analysis_vc_card_size = function(props){ // card短边尺寸 string return GEN.getProfileLimits({job:this.job,step:this.pcs_step,units:"mm"})[props].toFixed(2) } T_m_p.prototype.analysis_vc_array_size = function(props){ // array长边尺寸 string if(!this.array_step){return "_error"} return GEN.getProfileLimits({job:this.job,step:this.array_step,units:"mm"})[props].toFixed(2) } T_m_p.prototype.analysis_vc_pcs_count_on_panel = function(props){ // return "_todo" } T_m_p.prototype.analysis_stack_vias_number = function(props){ // via孔连续叠加的层数 var t = this; var res; // 找出 镭射孔 var laser_layers = [] for (var key in t.matrix) { var val = t.matrix[key] if(val.type == "laser_drill"){ laser_layers.push(val) } } if(laser_layers.length == 0){return "_error"} GEN.openStep({job:t.job,name:t.pcs_step}) laser_layers = laser_layers.sort(function(a,b){return Number(a.row)-Number(b.row)}) var laser_info = {} for(var i = 0; i < laser_layers.length-1; i++){ var start_layer = laser_layers[i].name var cover_layer = laser_layers[i+1].name GEN.workLayer({name:start_layer,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:cover_layer,use:'filter',mode:'cover'}) var count = GEN.getSelectCount() if(count>0){ if(!laser_info[start_layer]){ laser_info[start_layer] = {} } laser_info[start_layer].drill_connect_layer = cover_layer laser_info[start_layer].drill_connect_point = count } } // via孔连续叠加的层数 var via_vias_info = [] function analysis_via_number(layers){ if(layers.length < 2){return} var startlayer = layers[0].name + "_cover" GEN.selClearFeature() GEN.workLayer({name:layers[0].name,display_number:2,clear_before:'yes'}) GEN.selAllFeat() selCopyLayer({job:t.job,layer:startlayer}) var end_index = start_cover_next(startlayer,layers,0) via_vias_info.push(end_index+1) analysis_via_number(layers.slice(end_index)) } function start_cover_next(start, layers, end_index){ if(layers.length < 2){ GEN.deleteLayer({job:t.job,layer:start}) return end_index } layers = layers.slice(1) GEN.workLayer({name:start,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:layers[0].name,use:'filter',mode:'cover'}) var count = GEN.getSelectCount() if (count < 1) { GEN.deleteLayer({job:t.job,layer:start}) return ++end_index } var nextstartlayer = layers[0].name + "_cover" selCopyLayer({job:t.job,layer:nextstartlayer}) GEN.deleteLayer({job:t.job,layer:start}) return start_cover_next(nextstartlayer,layers,++end_index) } analysis_via_number(laser_layers.slice()) if (via_vias_info.length == 1){ res = via_vias_info[0] }else{ res = via_vias_info.reduce(function(a,b){return a-b>0?a :b}) } t.jobInfo.stack_vias_more = "no" if(GEN.getLayerCount({job:t.job}) > 14 && res >= 12){ t.jobInfo.stack_vias_more = "yes" } t.jobInfo.laser_info = laser_info; return res } T_m_p.prototype.analysis_layer_exist = function(props){ // 存在某某层? string return this.matrixInfo.matrix.hasOwnProperty(props) ? "yes" : "no" } T_m_p.prototype.analysis_laser_via_on_buried_hole = function(){ // todo return "_todo" } T_m_p.prototype.analysis_milling_bit_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_milling_length = function(){ // todo return "_todo" } T_m_p.prototype.analysis_board_has_attr = function(props){ // board层中检查存在01005属性物件时 GEN.openStep({job:this.job,name:this.pcs_step}) GEN.clearLayers() GEN.affectedLayer({affected:'yes',layer:this.matrixInfo.mBoardLayer,clear_before:'yes'}); GEN.selClearFeature() GEN.selectByFilter({attribute:props}) var res = GEN.getSelectCount() > 0? "yes" : "no" GEN.affectedLayer({affected:'no',mode:'all'}); GEN.selClearFeature() GEN.closeStep() return res } T_m_p.prototype.analysis_vc_src_EDGE_PLATING = function(props){ // ? 检查线路外形是否存在物件,存在则存yes var res = "no" var rout = this.matrixInfo.matrixVal.filter(function(v){return v.layer_type == "rout"}) // 找rout层 if(rout.length == 0){ return "error:cant find rout layer" } GEN.openStep({job:this.job, name:this.pcs_step}) GEN.affectedLayer({affected:'no',mode:'all'}) try { this.matrixInfo.mSignals.forEach(function(v){ // 用线路层逐层与rout层touch 找得到说明存在 GEN.workLayer({name:v.name,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:rout[0].name,mode:"touch",use:"filter"}) if( GEN.getSelectCount()>0){ throw "yes" } GEN.clearLayers() }) } catch (msg) { res = msg GEN.affectedLayer({affected:'no',mode:'all'}) GEN.selClearFeature() } GEN.closeStep() return res } T_m_p.prototype.analysis_edge_plating_length = function(){ // todo return "_todo" } T_m_p.prototype.analysis_glod_finger = function(){ // todo return "_todo" } T_m_p.prototype.analysis_glod_finger_area = function(){ // todo return "_todo" } T_m_p.prototype.analysis_solder_mask_side = function(){ // 检查防焊层所在面次 var solder_paste_layers = this.matrixInfo.matrixVal.filter(function(v){return v.layer_type == "solder_mask"}) var solder_paste_info= solder_paste_layers.map(function(v){return v.side}).reduce(function(a,b){ if(a.indexOf(b)<0){ a.push(b) } return a },[]) var res = "none" if(solder_paste_info.length == 0){ res = "none" } else if (solder_paste_info.length == 1) { res = /top/ig.test(solder_paste_info[0]) ? "top" : "bot" } else { res = "both" } return res } T_m_p.prototype.analysis_silk_screen_side = function(){ // 检查文字层所在面次 var solder_mask_layers = this.matrixInfo.matrixVal.filter(function(v){return v.layer_type == "solder_paste"}) var solder_mask_info= solder_mask_layers.map(function(v){return v.side}).reduce(function(a,b){ if(a.indexOf(b)<0){ a.push(b) } return a },[]) var res = "none" if(solder_mask_info.length == 0){ res = "none" } else if (solder_mask_info.length == 1) { res = /top/ig.test(solder_mask_info[0]) ? "top" : "bot" } else { res = "both" } return res } T_m_p.prototype.analysis_min_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_pth_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_npth_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_min_slot_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_slot_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_slot_drl_length = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_spec_slot_drl_size = function(){ // todo return "_todo" } T_m_p.prototype.analysis_max_spec_slot_drl_length = function(){ // todo return "_todo" } return new T_m_p({job:job, jobId:jobId, pcs_step:pcs_step, array_step:array_step,matrix:matrix}) } function smdAnalysis(props){ var job = props.job var steplist = props.steplist var layers = props.layers var res = {} steplist.forEach(function(step){ GEN.openStep({job:job,step:step}) layers.forEach(function(layer){ // 计算开窗 数量 if(layer.solderL){ GEN.workLayer({name:layer.solderL,display_number:2,clear_before:'yes'}) if (!res.hasOwnProperty(layer.solderL)){ res[layer.solderL] = {} } if(GEN.getProfile({job:job, step:step}).match(/\n/ig).length > 1){ GEN.selectByFilter({profile:'in'}) } else { GEN.selAllFeat() } res[layer.solderL].sm_opening_count = GEN.getSelectCount() GEN.selClearFeature() } // 分析最小smd宽高 GEN.workLayer({name:layer.signalL,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selectByFilter({attribute:props.attr}) var selCount = GEN.getSelectCount() if(selCount>0){ var tmp_layer = layer.signalL + "_tmp" selCopyLayer({job:job,layer:tmp_layer}) var symbols = GEN.getLayerSymsHist({job:job,layer:tmp_layer,step:step}) GEN.workLayer({name:tmp_layer,display_number:2,clear_before:'yes'}) var symbolInfo = symbolAnalysis({symbols:symbols,filterReg:/^rect/}) if (!res.hasOwnProperty(layer.signalL)){ res[layer.signalL] = {} } if(symbolInfo["min_width"]){ res[layer.signalL]["min_smd_width"] = symbolInfo["min_width"] } if(symbolInfo["min_length"]){ res[layer.signalL]["min_smd_length"] = symbolInfo["min_length"] } // 分析最小smd间距 // 创建一个checklist并且分析 var min_smd_pitch = smdPitch({job:job,step:step,layer:tmp_layer}) // min_smd_pitch // console.log('================= =======min_smd_pitch:' + min_smd_pitch); res[layer.signalL]["min_smd_pitch"] = min_smd_pitch // 分析开窗宽高 if(layer.solderL){ GEN.workLayer({name:layer.solderL,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'include'}) GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'cover'}) var solderL_tmp = layer.solderL + "_tmp" selCopyLayer({job:job,layer:solderL_tmp}) GEN.selClearFeature() GEN.workLayer({name:solderL_tmp,display_number:2,clear_before:"yes"}) var symbols_solder = GEN.getLayerSymsHist({job:job,layer:solderL_tmp,step:step}) var symbolInfo_solder = symbolAnalysis({symbols:symbols_solder,filterReg:/^rect/}) if(symbolInfo_solder["min_width"]){res[layer.signalL].min_smd_opening_width = symbolInfo_solder["min_width"]} if(symbolInfo_solder["min_length"]){res[layer.signalL].min_smd_opening_length = symbolInfo_solder["min_length"]} GEN.deleteLayer({job:job,layer:solderL_tmp}) } GEN.deleteLayer({job:job,layer:tmp_layer}) } }) GEN.closeStep() }) return res } function symbolAnalysis(props){ var symbols = Object.keys(props.symbols).reduce(function(a,b){ if(props.filterReg.test(b)){ var res = /^rect(\d+\.\d+|\d+)x(\d+\.\d+|\d+)/ig.exec(b).slice(1) var num1 = res[0], num2 = res[1] if(num1<=num2){ a.width.push(num1) a.length.push(num2) } else { a.width.push(num2) a.length.push(num1) } } return a },{width:[],length:[]}) var min_width,min_length; if(symbols.width.length){ min_width = symbols.width.reduce(function(a,b){return b-a > 0 ? a : b}) } if(symbols.length.length){ min_length = symbols.length.reduce(function(a,b){return b-a > 0 ? a : b}) } return { min_width:min_width0){ console.log("==========================>jinru 111111111") // 拷贝到_tmp var tmplayer = drill.layer + "_tmp" if(GEN.isLayerExists({job:job,layer:tmplayer})){GEN.deleteLayer({job:job,step:step,layer:tmplayer})} GEN.selCopyOther({dest:"layer_name",target_layer:tmplayer}) GEN.affectedLayer({affected:"no",mode:"all"}) GEN.selClearFeature(); [drill.start,drill.end].forEach(function(item, i){ GEN.workLayer({name:item,display_number:1,clear_before:"yes"}) GEN.COM("sel_ref_feat", {layers:tmplayer,use:"filter",mode:"touch",pads_as:"shape",f_types:"pad",polarity:"positive\;negative",include_syms:drill.symbol}) if(GEN.getSelectCount()>0){ var res = "" var pads = GEN.getFeatures({job:job,step:step,layer:item,options:"select"}) if(pads && pads.length) { pads = pads.filter(function(item){ return /^r\d+/.test(item.symbol) }) pads = pads.sort(function(a,b){ return parseInt(a.symbol) - parseInt(b.symbol) }) res = pads[0].symbol.slice(1) } if ( i == 0) { drill.drl_pad_top = res } else if (i==1){ drill.drl_pad_bot = res } } }) GEN.deleteLayer({job:job,step:step,layer:tmplayer}) } return drill }) return res } function bgaAnalysis(props){ var job = props.job var steplist = props.steplist var layers = props.layers; GEN.clearLayers() GEN.affectedLayer({affected:'yes',layer:layers.map(function(v){return v.signalL})}) GEN.selectByFilter({attribute:props.attr}) var count = GEN.getSelectCount() GEN.affectedLayer({affected:'no',mode:'all'}) GEN.selClearFeature() if(count == 0 ) { return {} } var res = {} steplist.forEach(function(step){ GEN.openStep({job:job,step:step}) layers.forEach(function(layer){ // 找出bga 拷贝到辅助层 GEN.workLayer({name:layer.signalL,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selectByFilter({attribute:props.attr}) var selCount = GEN.getSelectCount() if(selCount>0){ var tmp_layer = layer.signalL + "_tmp" selCopyLayer({job:job,layer:tmp_layer}) var symbols = GEN.getLayerSymsHist({job:job,layer:tmp_layer,step:step}) GEN.workLayer({name:tmp_layer,display_number:2,clear_before:'yes'}) // 分析数据 var syblist = _.values(symbols).reduce(function(a,b){ if (b.pad > 0 && b.line) { a.push({symbol:b.symbol, size:Number(b.size)}) } return a },[]) // 找到最小的bga分析 var min_symbols = syblist.sort(function(a,b){return a.size-b.size})[0] var min_symbols_info = min_symbols_anal({symbols:min_symbols, job:job, step:step, layer:layer}) if (!res.hasOwnProperty(layer.signalL)){ res[layer.signalL] = {} } res[layer.signalL].min1_bga_dia = myFixed(min_symbols_info["min_bga_size"],2) res[layer.signalL].min1_bga_sm_dia = myFixed(min_symbols_info["min_bga_openging_size"],2) res[layer.signalL].min1_bga_grid = myFixed(min_symbols_info["min_bga_pitch"],2) // 分析所有BGA var all_bga_min_pitch_info = all_bga_min_pitch_anal({job:job, step:step, layer:tmp_layer,solderLayer:layer.solderL}) res[layer.signalL].min2_bga_grid = myFixed(all_bga_min_pitch_info["bga_min_pitch"],2) res[layer.signalL].min2_bga_dia = myFixed(all_bga_min_pitch_info["bga_min_pitch_pad_size"],2) res[layer.signalL].min2_bga_sm_dia = myFixed(all_bga_min_pitch_info["bga_min_pitch_openging_size"],2) GEN.deleteLayer({job:job,layer:tmp_layer}) } }) GEN.closeStep() }) console.log(res); return res } function min_symbols_anal(props){ // 分析最 symbols var job = props.job var step = props.step var layer = props.layer var symbols = props.symbols var res = {} GEN.selClearFeature() GEN.selectByFilter({include_syms:symbols.symbol}) var tmp_layer = layer.signalL + "_tmp_1" selCopyLayer({job:job,layer:tmp_layer}) // 分析数据 // 尺寸 res.min_bga_size = symbols.size // 开窗大小 if(layer.solderL){ GEN.workLayer({name:layer.solderL,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'include'}) GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'cover'}) var solderL_tmp = layer.solderL + "_tmp" selCopyLayer({job:job,layer:solderL_tmp}) GEN.selClearFeature() GEN.workLayer({name:solderL_tmp,display_number:2,clear_before:"yes"}) var symbols_solder = GEN.getLayerSymsHist({job:job,layer:solderL_tmp,step:step}) res.min_bga_openging_size = _.values(symbols_solder).reduce(function(a,b){ if (b.pad > 0 && b.line) { if(/^rect|^oval/.test(b.symbol)){ b.size = b.width < b.height ? b.width : b.height } if(b.size) { a.push({symbol:b.symbol, size:Number(b.size)}) } } return a },[]).sort(function(a,b){return a.size-b.size})[0].size GEN.deleteLayer({job:job,layer:solderL_tmp}) } // 间距 res.min_bga_pitch = bgaPitch({job:job,step:step,layer:tmp_layer}) GEN.deleteLayer({job:job,layer:tmp_layer}) return res } function all_bga_min_pitch_anal(props){ // 分析所有bga中间距最小的 var job = props.job var step = props.step var layer = props.layer var symbols = props.symbols var solder_layer = props.solderLayer var res = {} var ck = "tmp_chk" if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck }) } // 创建并运行 var tmpItem = { name: "bgaPitch", nact: 1, action: "valor_analysis_signal", erf: PAR.erf, params: { pp_layer: ".affected", pp_spacing: 20, pp_selected: "All", pp_r2c: 10, pp_d2c: 15, pp_sliver: 8, pp_min_pad_overlap: 5, pp_check_missing_pads_for_drills: "Yes", pp_use_compensated_rout: "Skeleton", pp_sm_spacing: "Yes", pp_tests: "Spacing", pp_check_missing_pads_for_drills:"Yes" } } if(PAR.erf){ tmpItem.erf = PAR.erf } GEN.createChklist({ // 创建checklist chklist: ck, items: [tmpItem] }) GEN.chklistShow({ chklist: ck }) GEN.affectedLayer({ affected: "yes", layer: layer, clear_before: "yes" }) GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' }) var tmp_layer1 = "mk_1_"+layer+"_pitch" var tmp_layer2 = "ms_1_"+layer+"_pitch" if(GEN.isLayerExists({job:job,layer:tmp_layer1})){ GEN.deleteLayer({job:job,layer:tmp_layer1}) } if(GEN.isLayerExists({job:job,layer:tmp_layer2})){ GEN.deleteLayer({job:job,layer:tmp_layer2}) } GEN.COM("chklist_create_lyrs,chklist="+ck+",severity=3,suffix=pitch"); GEN.workLayer({name:tmp_layer2,display_number:1,clear_before:'yes'}); GEN.selectByFilter({attribute:[{attribute:".string",text:"bga_pitch"}]}) var tmp_layer = tmp_layer2 + "_tmp" selCopyLayer({job:job,layer:tmp_layer}) GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'}); var symbols = GEN.getLayerSymsHist({job:job,layer:tmp_layer,step:step}) // 获取最小smd间距 var min_symbol = _.values(symbols).sort(function(a,b){return Number(a.size)-Number(b.size)})[0] res.bga_min_pitch = min_symbol.size // 所有BGA中间距最小的PAD大小 GEN.selClearFeature() GEN.selectByFilter({include_syms:min_symbol.symbol}) var min_pitch_layer = tmp_layer + "_min" selCopyLayer({job:job,layer:min_pitch_layer}) GEN.workLayer({name:layer,display_number:1,clear_before:'yes'}); GEN.selClearFeature() GEN.selRefFeat({layers:min_pitch_layer,use:'filter',mode:'touch'}) var min_pad_layer = layer + "_min_pad" selCopyLayer({job:job,layer:min_pad_layer}) GEN.workLayer({name:min_pad_layer,display_number:1,clear_before:'yes'}); var min_pad_symbols = GEN.getLayerSymsHist({job:job,layer:min_pad_layer,step:step}) var min_pad_symbol = _.values(min_pad_symbols).sort(function(a,b){return Number(a.size)-Number(b.size)})[0] res.bga_min_pitch_pad_size = min_pad_symbol.size if(solder_layer){ // 最小pitch开窗大小 GEN.workLayer({name:solder_layer,display_number:1,clear_before:'yes'}); GEN.selClearFeature() GEN.selRefFeat({layers:min_pitch_layer,use:'filter',mode:'touch'}) var solder_layer_tmp = solder_layer + "_tmp" selCopyLayer({job:job,layer:solder_layer_tmp}) GEN.selClearFeature() GEN.workLayer({name:solder_layer_tmp,display_number:2,clear_before:"yes"}) var symbols_solder = GEN.getLayerSymsHist({job:job,layer:solder_layer_tmp,step:step}) var symbols_solder_list = _.values(symbols_solder).filter(function(v){return /\d+/ig.test(v.size)}) if(symbols_solder_list.length){ res.bga_min_pitch_openging_size = symbols_solder_list.sort(function(a,b){return Number(a.size)-Number(b.size)})[0].size } GEN.deleteLayer({job:job,layer:solder_layer_tmp}) } GEN.deleteLayer({job:job,layer:min_pad_layer}) GEN.deleteLayer({job:job,layer:min_pitch_layer}) GEN.deleteLayer({job:job,layer:tmp_layer}) GEN.deleteLayer({job:job,layer:tmp_layer1}) GEN.deleteLayer({job:job,layer:tmp_layer2}) return res } function bgaPitch(props){ var job = props.job var step = props.step var layer = props.layer var ck = "tmp_chk" if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck }) } // 创建并运行 var tmpItem = { name: "bgaPitch", nact: 1, action: "valor_analysis_signal", params: { pp_layer: ".affected", pp_spacing: 20, pp_selected: "All", pp_r2c: 10, pp_d2c: 15, pp_sliver: 8, pp_min_pad_overlap: 5, pp_check_missing_pads_for_drills: "Yes", pp_use_compensated_rout: "Skeleton", pp_sm_spacing: "Yes", pp_tests: "Spacing", pp_check_missing_pads_for_drills:"Yes" } } if(PAR.erf) { tmpItem.erf = PAR.erf } GEN.createChklist({ // 创建checklist chklist: ck, items: [tmpItem] }) GEN.chklistShow({ chklist: ck }) GEN.affectedLayer({ affected: "yes", layer: layer, clear_before: "yes" }) GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' }) var tmp_layer1 = "mk_1_"+layer+"_pitch" var tmp_layer2 = "ms_1_"+layer+"_pitch" if(GEN.isLayerExists({job:job,layer:tmp_layer1})){ GEN.deleteLayer({job:job,layer:tmp_layer1}) } if(GEN.isLayerExists({job:job,layer:tmp_layer2})){ GEN.deleteLayer({job:job,layer:tmp_layer2}) } GEN.COM("chklist_create_lyrs,chklist="+ck+",severity=3,suffix=pitch"); GEN.workLayer({name:tmp_layer2,display_number:1,clear_before:'yes'}); GEN.selectByFilter({attribute:[{attribute:".string",text:"bga_pitch"}]}) var tmp_layer = tmp_layer2 + "_tmp" selCopyLayer({job:job,layer:tmp_layer}) GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'}); var features = GEN.getFeatures({job:job,step:step,layer:tmp_layer}) var tmp = features.map(function(v){ var num = Math.sqrt((v.xe-v.xs)*(v.xe-v.xs) + (v.ye-v.ys)*(v.ye-v.ys))*1000 return num.toFixed(4) }) var res = tmp.sort(function(a,b){return a-b})[0] GEN.deleteLayer({job:job,layer:tmp_layer}) GEN.deleteLayer({job:job,layer:tmp_layer1}) GEN.deleteLayer({job:job,layer:tmp_layer2}) // 矩阵 return res } function hasAttr(props){ // 判断层 有没有部分属性 var job = props.job // 有没有smd和bga属性的物件 var attr = props.attr var step = props.step var res = false try { var layers = props.layers GEN.openStep({job:job,name:step}) for (var i = 0;i 0){ throw true } } GEN.clearLayers() GEN.closeStep() } catch (msg) { res = msg GEN.clearLayers() GEN.closeStep() } return res } function myFixed(str, num) { if(/^[1-9][0-9]*([.][0-9]+)?$/.test(str)){ return Number(str).toFixed(num) } else { return str } } function createOutline(props){ var job = props.job var step = props.step var matrix = props.matrix var outlines = Object.keys(matrix).filter(function(v){return /^outline$|^rout$/ig.test(v)}) var drill_layer = Object.keys(matrix).filter(function(v){return matrix[v].layer_type=="drill" && matrix[v].context == "board"}) var tmp_outline if(outlines.length){ if( outlines.length > 1 && outlines.indexOf("outline")>=0){ tmp_outline = "outline" if(cl(tmp_outline)) { return true }else{ return cl("rout") } } else { return cl(outlines[0]) } }else{return false} function cl(l){ GEN.openStep({job:job, name:step}) GEN.affectedLayer({affected:'no',mode:'all'}) GEN.workLayer({name:l,display_number:2,clear_before:"yes"}) GEN.selClearFeature() GEN.COM("sel_cut_data,det_tol=1,con_tol=1,rad_tol=0.1,filter_overlaps=no,delete_doubles=no,use_order=yes,ignore_width=yes,ignore_holes=none,start_positive=yes,polarity_of_touching=same") var tmp_layer = l+"+++" GEN.selRefFeat({layers:drill_layer[0],use:'filter',mode:'touch'}) if(GEN.getSelectCount() > 0){ var tmp_outline = l + "_tmp" selCopyLayer({job:job,layer:tmp_outline}) GEN.workLayer({name:l,display_number:2,clear_before:"yes"}) GEN.selAllFeat() GEN.selDelete() GEN.workLayer({name:tmp_outline,display_number:2,clear_before:"yes"}) GEN.COM("sel_surf2outline,width=15") GEN.selAllFeat() selCopyLayer({job:job,layer:l}) GEN.workLayer({name:l,display_number:2,clear_before:"yes"}) GEN.selClearFeature() GEN.selCreateProfile() GEN.deleteLayer({job:job, layer:tmp_layer}) GEN.deleteLayer({job:job, layer:tmp_outline}) return true } GEN.deleteLayer({job:job, layer:tmp_layer}) return false } }