Commit e3c3cc73 authored by Scott Sun's avatar Scott Sun

scott

parent 9414cfdb
/*
NAME:
DESCRIPTION: 客户数据分析
PARAMETER:
[
{
name : 'pcs_step',
title : 'pcsStep名',
type : 'LineEdit',
property : {tool_tip : 'pcs step名,默认是cad'}
},
{
name : 'cam_type',
title : 'cam_type',
type : 'LineEdit',
property : {tool_tip : 'cam_type'}
},
{
name : 'vc_src_01005_pad_result',
title : 'vc_src_01005_pad_result',
type : 'LineEdit',
property : {tool_tip : 'vc_src_01005_pad_result'}
},
{
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:'是否自动保存料号开关'
}
},
{
name : 'export_path',
title : '导出路径',
type : 'LineEdit',
property : {tool_tip : '导出路径'}
},
{
name : 'export_mode',
title : '导出模式',
type : 'RadioBox',
property : {
item_list:[
{name:'tar_gzip',text:'tar_gzip'},
{name:'tar',text:'tar'},
{name:'xml',text:'xml'},
{name:'directory',text:'directory'},
],
tool_tip:'导出模式'
}
},
{
name : 'export_submode',
title : '导出方式',
type : 'RadioBox',
property : {
item_list:[
{name:'full',text:'full'},
{name:'partial',text:'partial'},
],
tool_tip:'导出方式'
}
}
]
VERSION_HISTORY:
V1.00 2020 3-30 Scott
HELP:
<html><body bgcolor="#DDECFE">
<font size="3" color="#003DB2"><p>功能简介</p></font>
<p> 客户数据分析</p>
<br>
<font size="3" color="#003DB2"><p>参数配置</p></font>
<p> 客户参数 </p>
<font size="3" color="#003DB2"><p>注意事项</p></font>
<p> ● 无 </p>
<br>
</body></html>
*/
// 引入模块 包
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 }
});
}
}
var Status = 'ok';
var resultData = [];
var ALL = {}
var Omatrix = {};
try {
console.log("=============================================>anaysis_start");
var par = PAR;
var vc_src_01005_pad_result = par.vc_src_01005_pad_result
if(vc_src_01005_pad_result == ""){
vc_src_01005_pad_result = ".pth_pad"
}
if(par.erf == ""){delete PAR.erf}
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})
_.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.odb_name,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
GEN.selAllFeat()
if(GEN.getSelectCount()>0){
unSelect()
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.odb_name,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
var tmp_layer = v.drl_start + "tmp"
GEN.workLayer({name:v.drl_start,display_number:2,clear_before:'yes'})
GEN.selCopyOther({dest:'layer_name',target_layer:tmp_layer,invert:'no',dx:0,dy:0,size:0})
GEN.workLayer({name:tmp_layer,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:v.odb_name,use:'filter',mode:'cover'})
if(GEN.getSelectCount()> 0){GEN.selDelete()}
GEN.workLayer({name:v.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
unSelect()
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){
unSelect()
if(GEN.getSelectCount() > 0){
GEN.COM("cur_atr_set,attribute=.drill,option=non_plated")
GEN.COM("sel_change_atr,mode=add")
}
}
GEN.deleteLayer({job:job,layer:[tmp_layer]})
}
}
})
GEN.clearLayers()
// * new 钻孔叠构
var cam_drill_structure = []
var stack_drills = _.values(matrix).filter(function(item){
return item.layer_type == "drill" && item.context == "board"
})
var layerCount = GEN.getLayerCount({job:job})
stack_drills.forEach(function(drill){
GEN.clearLayers()
GEN.selClearFeature()
var drill_info = {}
var drl_start_num = drill.drl_start_num -0
var drl_end_num = drill.drl_end_num-0
drill_info.drl_start_num = drl_start_num
drill_info.drl_end_num = drl_end_num
var drl_side = "None"
if(layerCount/2 >= drl_start_num){
drl_side = "Top"
} else {
drl_side = "Bot"
}
drill_info.drl_side = drl_side
var drl_filler = "None"
if(drill.type == "laser_drill"){
drill_info.drl_type = "Laser"
drill_info.drl_name = "Laser" + drl_start_num + "-" + drl_end_num
drill_info.drl_tech = "LDD"
// 计算此层的理论 top bot
if(drl_side == "Top"){
if((drl_start_num-1)==0){ drl_filler = "None" }
else {
var top_l = "ftdrill" + (drl_start_num-1) + "-" + (drl_end_num-1) + "l"
if(GEN.isLayerExists({job:job, layer:top_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:top_l,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:drill.odb_name,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drl_filler="Via Filling"
}
}
}
var bot_l = "ftdrill" + (drl_start_num+1) + "-" + (drl_end_num+1) + "l"
if(GEN.isLayerExists({job:job, layer:bot_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:bot_l,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_overlap = "Yes"
} else {
drill_info.drl_overlap = "No"
}
}else{ drill_info.drl_overlap = "No" }
}else if (drl_side == "Bot"){
if((drl_end_num-layerCount)==0){ drl_filler = "None" }
else {
var top_l = "ftdrill" + (drl_start_num+1) + "-" + (drl_end_num+1) + "l"
if(GEN.isLayerExists({job:job, layer:top_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:top_l,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:drill.odb_name,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drl_filler="Via Filling"
}
}
}
var bot_l = "ftdrill" + (drl_start_num-1) + "-" + (drl_end_num-1) + "l"
if(GEN.isLayerExists({job:job, layer:bot_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:bot_l,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_overlap = "Yes"
}else {
drill_info.drl_overlap = "No"
}
}else{ drill_info.drl_overlap = "No" }
}
} else {
GEN.clearLayers()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selectByFilter({attribute:[{attribute:".drill",option:"plated"}]})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_type = "PTH"
if(drl_end_num - drl_start_num == 1){drl_filler = "Resin Plugin"}
drill_info.drl_name = "PTH" + drl_start_num + "-" + drl_end_num
}else{
drill_info.drl_type = "NPTH"
drill_info.drl_name = "NPTH" + drl_start_num + "-" + drl_end_num
}
}
drill_info.drl_filler = drl_filler
drill_info.drl_zones = "{A}"
cam_drill_structure.push(drill_info)
})
var is_via_filling = cam_drill_structure.filter(function(v){return v.drl_filler == "Via Filling"})
if(is_via_filling.length>0){
cam_drill_structure = cam_drill_structure.map(function(item){
if(item.drl_type=="Laser" && item.drl_filler=="None"){
item.drl_filler = "Via Filling"
}
return item
})
}
save_job_info({
jobid: JobId,
jobinfohash: {cam_drill_structure: JSON.stringify(cam_drill_structure)}
})
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})
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})
var hasProfile = GEN.getProfile({job:job, step:pcs_step})
if(hasProfile.match(/\n/ig).length == 1){
throw "创建profile失败"
} else {
GEN.affectedLayer({affected:'yes',mode:'all'})
GEN.selectByFilter({profile:"out"})
if(GEN.getSelectCount() > 0){
GEN.selDelete()
}
}
} else {
GEN.affectedLayer({affected:'yes',mode:'all'})
GEN.selectByFilter({profile:"out"})
if(GEN.getSelectCount() > 0){
GEN.selDelete()
}
}
GEN.closeStep()
// * profile 和 拼版
var pandle_step = step_list.map(function(v){
var type = "unknow";
if(/^cad|^pcs/ig.test(v)){
type = "pcs"
} else if (/^arr|^stp/ig.test(v)) {
type = "array"
}
var panel_info = {job_id:JobId,step_name:v,step_type:type}
GEN.openStep({job:job,name:v})
GEN.clearLayers()
GEN.selClearFeature()
var profileLimits = GEN.getProfileLimits({job:job,step:v,units:"mm"})
if(profileLimits){
panel_info.size_x = Number(profileLimits.xsize).toFixed(3)
panel_info.size_y = Number(profileLimits.ysize).toFixed(3)
}
panel_info.datum_x = 0
panel_info.datum_y = 0
panel_info.margin = {"margin_top": 0, "margin_left": 0, "margin_right": 0, "margin_bottom": 0, "allow_margin_top": 0, "allow_margin_left": 0, "allow_margin_right": 0, "allow_margin_bottom": 0}
var profile = GEN.getProfile({job:job,step:v,units:"mm"}).split("\n")
if(profile.length>=1){
var tmp = profile.slice(1)
tmp = tmp.map(function(v){
if(v[0]==="#"){v = v.slice(1)}
return v
})
panel_info.profile = tmp.join("\n")
} else {
profile = profile.map(function(v){
if(v[0]==="#"){v = v.slice(1)}
return v
})
panel_info.profile = profile.join("\n")
}
for(var key in profileLimits){
profileLimits[key] = Number(profileLimits[key])
}
panel_info.profile_limits = profileLimits
panel_info.attr_data= {}
panel_info.extra_data= {}
var repeat = GEN.getSR1({job:job,step:v,units:"mm"})
var step_repeat = {}
repeat.forEach(function(item, i){
step_repeat[String(i)] = {
x:item.xa,
y:item.ya,
dx: item.dx,dy: item.dy,
nx:item.nx,ny:item.ny,
// gapX:item.xsize,gapY:item.ysize,
step:item.step,
angle:item.angle,
mirror:item.mirror == "no" ? 0 : 1,
step_name:item.step,
step_type:/cad|pcs|card/ig.test(item.step)? "pcs" : "array",
}
})
panel_info.step_repeat = step_repeat
save_panel_info({info:panel_info, table:"pdm_job_panelizer_step"})
GEN.closeStep()
return {name:v, type:type}})
// glod_finger
var gold_fingers = Object.keys(tmp_matrix).filter(function(v){return /^enig_top$|^enig_bot$/ig.test(v)})
if(gold_fingers.length){
gold_fingers = gold_fingers.map(function(v){
var type = (v=="enig_top") ? "top" : "bot"
return {name:v, type:type}
})
}
ALL.gold_fingers = gold_fingers
GEN.closeStep()
var config = {
jobInfo: {
layer_count: ["signal","power_ground"], // Board属性的signal或者power_ground层
pcs_size_x: {api:"vc_card_size", props:"xsize"}, // card短边尺寸 // ? 保留小数
pcs_size_y: {api:"vc_card_size", props:"ysize"}, // card长边尺寸 // ? 保留小数
array_size_x: {api:"vc_array_size", props:"xsize"}, // ! array短边尺寸 需要arr_step // ? 保留小数
array_size_y: {api:"vc_array_size", props:"ysize"}, // ! array长边尺寸 需要arr_step // ? 保留小数
vc_pcs_count_on_panel: true, // array中pcs的数量 ! 需要arr_step
pcs_count_on_array: true,
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, // via孔在埋孔上时,存yes
milling_bit_size: false, // todo 检查array中pcs的最小间距值
milling_length_card: true,
milling_length_array: true,
vc_src_01005_pad_result: {api:"board_has_attr", props:vc_src_01005_pad_result}, // 本地使用 .pth_pad ats 01005_pad
ATS_technology_25dc: {api:"layer_exist", props:["bot_coverlay","top_coverlay"]}, // yes|no:存在cavity层别时存yes
ATS_technology_25dr: {api:"layer_exist", props:["bot_coverlay","top_coverlay"]}, // yes|no:存在cavity层别时存yes
// vc_src_EDGE_PLATING: true, // yes|no:检查线路外形是否存在物件,存在则存yes // !料号需要有rout层
vc_src_EDGE_PLATING: {api:"layer_exist2", props:["fab_page2"]}, // fab_page2
edge_plating_length: true, // todo 检查线路外形处物件的长度
gold_finger: false, //
glod_finger_area: false, //
ATS_sm_side: true, // top|bot|both:检查防焊层所在面次 ATS_sm_side
vc_id_print_side: true, // top|bot|both:检查文字层所在面次 vc_id_print_side
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("========================================error:");
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_tool_info = {};
var drillLayers = analysis_obj.matrixInfo.mDrills;
var pcs_steps = [par.pcs_step]
var arr_steps = [par.array_step]
drillLayers.forEach(function(item){
var layer = item.name
if(pcs_steps.length > 0){
pcs_steps.forEach(function(step){
if(!GEN.isLayerEmpty({job:job,step:step,layer:layer})){
GEN.COM("tools_set,layer="+layer+",slots=by_length")
console.log(_.toString({job:job,step:step,layer:layer,units:"mm"}));
var tool = GEN.getTool({job:job,step:step,layer:layer,units:"mm"});
if(drill_tool_info[layer]){
Object.keys(tool).forEach(function(hashkey){
if(drill_tool_info[layer][hashkey]){
if(!drill_tool_info[layer][hashkey].pcs_count){drill_tool_info[layer][hashkey].pcs_count = 0}
drill_tool_info[layer][hashkey].pcs_count += Number(tool[hashkey].count) ;
}
})
}else{
drill_tool_info[layer] = tool ;
Object.keys(tool).forEach(function(hashkey){
if(!drill_tool_info[layer][hashkey].pcs_count){drill_tool_info[layer][hashkey].pcs_count = 0}
drill_tool_info[layer][hashkey].pcs_count += Number(tool[hashkey].count) ;
})
}
}
})
}
if(arr_steps.length > 0){
arr_steps.forEach(function(step){
if(GEN.isStepExists({job:job,step:step})){
if(!GEN.isLayerEmpty({job:job,step:step,layer:layer})){
var tool = GEN.getTool({job:job,step:step,layer:layer,units:"mm"});
if(drill_tool_info[layer]){
Object.keys(tool).forEach(function(hashkey){
if(drill_tool_info[layer][hashkey]){
if(!drill_tool_info[layer][hashkey].array_count){drill_tool_info[layer][hashkey].array_count = 0}
drill_tool_info[layer][hashkey].array_count += Number(tool[hashkey].count) ;
}
})
}else{
drill_tool_info[layer] = tool ;
Object.keys(tool).forEach(function(hashkey){
if(!drill_tool_info[layer][hashkey].array_count){drill_tool_info[layer][hashkey].array_count = 0}
drill_tool_info[layer][hashkey].array_count += Number(tool[hashkey].count) ;
})
}
}
}
})
}
})
// 删除
db.query("",function(q){
return q.deleteRow({
table:'pdm_job_cam_drill',
where:{job_id:JobId}
})
});
var seq_index = 1 ;
Object.keys(drill_tool_info).forEach(function(layer){
var datalist = []
var tool_num = 1 ;
_.values(drill_tool_info[layer]).sort(function(a,b){return a.drill_size - b.drill_size}).forEach(function(item){
var layer_name = layer
var drill_type = item.type
if(matrix[layer].type == "laser_drill" && /^[^\d]+(\d+)-(\d+)[^\d]?$/.test(layer_name)){
drill_type = "laser"
var info_drilll = /^[^\d]+(\d+)-(\d+)[^\d]?$/.exec(layer_name);
layer_name = "l" + info_drilll[1] + "-" + info_drilll[2];
} else if(layer_name === "ftdrill"){
layer_name = "drill"
} else if(/^[^\d]+(\d+)-(\d+)[^\d]?$/.test(layer_name)) {
var info_drilll = /^[^\d]+(\d+)-(\d+)[^\d]?$/.exec(layer_name);
layer_name = "d" + info_drilll[1] + "-" + info_drilll[2];
}
if(matrix[layer].type == "bury_drill"){
drill_type = "via"
}
var data = {
job_id: JobId,
layer_name: layer_name,
tool_num: "T" + tool_num,
tool_flag: tool_num,
tool_type: item.shape,
drill_type:drill_type,
// drill_size : item.drill_size,
drill_slot_length: Number(item.slot_len),
finish_size : Number(item.finish_size).toFixed(3),
finish_slot_length: Number(item.slot_len),
// size_tol_lower: item.min_tol,
// size_tol_upper: item.max_tol,
pcs_count: item.pcs_count || 0,
array_count: item.array_count || 0,
seq: seq_index + tool_num/100,
attr_data: {"org_layer_name":layer}
}
datalist.push(data)
tool_num++
})
seq_index++
// datalist存入
datalist.forEach(function(data){
db.query("",function(q){
return q.insertRow({
table:'pdm_job_cam_drill',
data:data
})
});
})
})
console.log("=============================> 6 set smd bga")
var allStep = GEN.getStepList({job:job})
allStep.forEach(function(step){
GEN.openStep({job:job,name:step})
GEN.affectedLayer({affected:'no',mode:'all'})
GEN.clearLayers()
if(GEN.GEN_TYPE == "genesis"){
GEN.COM("chklist_single,action=valor_cleanup_set_smd,show=yes")
GEN.COM("chklist_cupd,chklist=valor_cleanup_set_smd,nact=1,params=((pp_layer=.type=signal|mixed&side=top|bottom)(pp_drill=No)(pp_rotate=No)(pp_ignore_covered=Yes)(pp_sm=No)(pp_types=Square\;Rect\;Oval)(pp_other=)(pp_delete=No)),mode=regular")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("chklist_close,chklist=valor_cleanup_set_smd,mode=hide")
}else{
GEN.COM("chklist_single,show=yes,action=valor_cleanup_set_smd")
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")
GEN.COM("get_user_name")
GEN.COM("get_job_path,job="+job)
GEN.COM("disp_on")
GEN.COM("origin_on")
GEN.COM("chklist_cnf_act,chklist=valor_cleanup_set_smd,nact=1,cnf=no")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("skip_next_pre_hook")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("get_user_name")
GEN.COM("skip_current_command")
GEN.COM("disp_on")
GEN.COM("origin_on")
GEN.COM("show_tab,tab=Checklists,show=no")
}
// top bottom 层smd排除掉 r\d开头的圆形smd // 与开窗touch 碰不到的删除属性
analysis_obj.matrixInfo.mOuters.forEach(function(item){
var layer = item.signalL
var oping_layer = layer.solderL
GEN.workLayer({name:layer,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
var symbols_tmp = GEN.getLayerSymsHist({job:job,step:step,layer:layer})
var syms = Object.keys(symbols_tmp)
var filter_syms = syms.filter(function(item){
if(/^rect(\d+\.\d+|\d+)x(\d+\.\d+|\d+)/ig.test(item)){
var res = /^rect(\d+\.\d+|\d+)x(\d+\.\d+|\d+)/ig.exec(item).slice(1)
var num1 = res[0], num2 = res[1]
if(num1<3 || num2<3){return true}
}
return /^r\d+/.test(item)}
)
if(filter_syms.length){
var filter_syms = filter_syms.join(";")
GEN.selectByFilter({attribute:".smd", include_syms:filter_syms, profile:"in"})
if(GEN.getSelectCount()>0){
GEN.COM("sel_delete_atr,attributes=.smd")
}
}
if(oping_layer){
GEN.COM("filter_atr_set,filter_name=popup,condition=yes,attribute=.smd")
GEN.COM("sel_ref_feat,layers="+oping_layer+",use=filter,mode=disjoint,pads_as=shape,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,include_syms=,exclude_syms=")
GEN.COM("COM filter_reset,filter_name=popup")
}
})
GEN.closeStep()
})
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;
bgaInfo = bgaAnalysis({job:job,steplist:[pcs_step],layers:analysis_obj.matrixInfo.mOuters,attr:".bga"})
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})
console.log("=============================> 13 save copperArea copper_distribution")
var copper_distribution_steplist= [pcs_step, array_step];
copper_distribution_steplist.forEach(function(step){
if(step){
GEN.openStep({ job: job, name: step })
// 铜面积 分step
var copper_percent_tmp = 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_tmp));
copper_percent_tmp.forEach(function(item){
var save_info = {
jobid: JobId,
layer: item.layer,
}
if(/^cad/ig.test(step)){
save_info.layerinfohash = {
card_copper_distribution: item.copper_percent
}
} else if(/^stp/ig.test(step)){
save_info.layerinfohash = {
array_copper_distribution: item.copper_percent
}
}
save_layerinfo(save_info)
})
GEN.closeStep()
}
})
var info = {
min_line_width: ["line","user_nor_line"],
min_line_spacing: ["l2l"],
min_line2pad: ["p2line","user_bga2nor_line","user_smd2nor_line"],
min_pad2pad: ["p2p", "smd2smd", "smd2pad","via2via","bga2pad"],
min_ar_laser:["laser_via_ar"],
min_ar_via:["via_ar"],
min_ar_pth:["pth_ar"],
min_ar_npth:["npth_ar"]
}
save_job_info({
jobid: JobId,
jobinfohash: {ATS_surface_area_base_on:"Card"}
})
var jobpath = GEN.getJobPath({job:job})
// if(GEN.GEN_TYPE == "genesis"){
// jobpath = GEN.getJobPath({job:job})
// } else {
// jobpath = "/home/local_db/server_db/jobs/"+job
// }
mkPath(jobpath,["user","opcam","steps"])
stepList.forEach(function(step){
GEN.openStep({ job: job, name: step })
// 曝光
analysis_obj.matrixInfo.mOuters.forEach(function(item){
if(ALL.gold_fingers.length>0){
var tmp_gold_info = {}
ALL.gold_fingers.forEach(function(item2){
tmp_gold_info[item2.type] = item2.name
})
var layer_gold_type = /top/ig.test(item.signalL) ? "top" : "bot"
if(tmp_gold_info[layer_gold_type]){
var tmp_info = GEN.copperArea({layer1:tmp_gold_info[layer_gold_type],resolution_value:1})
// var tmp_info = GEN.exposedArea({layer1:item.signalL,mask1:tmp_gold_info[layer_gold_type]})
var tmp_data = {}
if(layer_gold_type == "top") {
tmp_data.sf_area_ref_layer_front = tmp_gold_info[layer_gold_type]
tmp_data.sf_area_gold_area_front = tmp_info.area
}
if(layer_gold_type == "bot"){
tmp_data.sf_area_ref_layer_back = tmp_gold_info[layer_gold_type]
tmp_data.sf_area_gold_area_back = tmp_info.area
}
save_job_info({
jobid: JobId,
jobinfohash: tmp_data
})
save_layerinfo({
jobid: JobId,
layer: item.signalL,
layerinfohash: {
sf_area_ref_layer: tmp_gold_info[layer_gold_type],
sf_area_gold_area: tmp_info.area
}
})
}
}
if(item.solderL){
var tmp_info = GEN.copperArea({layer1:item.solderL,resolution_value:1})
// 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;
// todo carbon 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_area
}
})
}
})
GEN.clearLayers()
GEN.affectedLayer({ affected: 'no', mode: 'all' })
console.log("==================================> Drill analysis")
// 钻孔
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:tmp_matrix[v]["drl_start"],end:tmp_matrix[v]["drl_end"]}
})
var drillRes = analysisDrill(drillToSignals,step) // 钻孔分析结果
console.log("===============drillRes:" + _.toString(drillRes));
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("==================================> chk signals analysis")
// 创建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]
})
// signal层分析结果
var res = analysisChkAttr({layers:signalLayers, info:info, step:step, job:job, oChecklistName:oChecklistName,jobpath:jobpath})
// 数据入库
Object.keys(res).forEach(function(key){
var val = res[key]
for(var key2 in val){
if(key2 == "min_ar_npth"){
if(Number(val[key2]) == 0 || Number(val[key2]) == 999){
delete val.min_ar_npth
}
}
}
save_layerinfo({
jobid: JobId,
layer: key,
layerinfohash: val
})
})
GEN.closeStep()
})
IKM.msg("end wait for save")
// 保存
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"})
}
IKM.msg("export")
// 导出
if(par.export_path != "" && par.export_mode != "" && par.export_submode != "" ){
if(fs.exists(par.export_path)){
if(GEN.GEN_TYPE == "genesis"){
GEN.COM("export_job,job="+job+",path="+par.export_path+",mode="+par.export_mode+",submode="+par.export_submode+",overwrite=yes")
} else {
GEN.COM("export_job",{job:job,path:par.export_path,mode:par.export_mode,submode:par.export_submode,overwrite:"yes",format:"genesis",output_name:job})
GEN.COM("disp_on")
GEN.COM("origin_on")
}
} else {
resultData.push({ type: "error", title: "导出路径不存在!", detail: [{ desc: par.export_path }] });
}
}
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 UPLOAD_LAYER_MATRIX(props){
var job = props.job
props.jobcategory = props.jobcategory || "work"
var matrix = ANALYSIS_STACKUP({job:job, jobcategory:props.jobcategory});
Omatrix = matrix
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 == 'ftdrill'){
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 (/^ftdrill(\d+)-(\d+)/.test(layer.odb_name)){ // /^d(\d+)\-(\d+)$/
var tmp = /^ftdrill(\d+)-(\d+)/.exec(layer.odb_name)
var drl_star = tmp[1];
var drl_end = tmp[2];
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.name = 'laser' + drl_star + '-' + drl_end;
layer.type = 'laser_drill'; // 镭射
} else if( drl_star == 1 || drl_end == layer_count ){
layer.name = 'drill' + drl_star + '-' + drl_end;
layer.type = 'blind_drill'; // 埋孔
} else{
layer.name = 'drill' + drl_star + '-' + drl_end;
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})
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
// }
// }
if(Omatrix[layer] && Omatrix[layer].name){
// if(!(/^drill/ig.test(Omatrix[layer].tl_name))){
layer = Omatrix[layer].name
// }
}
var layerinfohash = props.layerinfohash;
Object.keys(layerinfohash).forEach(function(key){
var val = layerinfohash[key];
if(val && val != ""){
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, layer:layer},
data:{value:val},
})
});
}
}
})
}
function save_stack_info(props){
var info = props.info
var table = "pdm_job_stack_drills"
info.job_id = JobId
var drl_name = info.drl_name
db.query("",function(q){
return q.deleteRow({
table:table,
where:{job_id:JobId, drl_name: drl_name}
})
});
console.log(_.toString(info))
var Re = db.query("",function(q){
return q.insertRow({
table:table,
data:info,
return_field:'job_id',
})
});
}
function save_panel_info(props){
var info = props.info
var table = props.table
info.job_id = JobId
var job_id = info.job_id || JobId
var step_name = info.step_name
db.query("",function(q){
return q.deleteRow({
table:table,
where:{job_id:job_id, step_name: step_name}
})
});
db.query("",function(q){
return q.insertRow({
table:table,
data:info
})
});
}
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"}
var tmp = GEN.getProfileLimits({job:this.job,step:this.array_step,units:"mm"})
var size1 = Number(tmp.xsize)
var size2 = Number(tmp.ysize)
if(size1 > size2){
var tmpsize = size2
size2 = size1
size1 = tmpsize
}
if(props == "xsize"){
return size1.toFixed(2)
}
if(props == "ysize"){
return size2.toFixed(2)
}
}
T_m_p.prototype.analysis_vc_pcs_count_on_panel = function(props){ //
if(!this.array_step){return "_error"}
var has_step = has_steps({job:this.job, pcs_step:this.pcs_step ,array_step:this.array_step}) // 有无拼版关系
if(has_step){
// arr 中 pcs数量
var tmp = GEN.getRepeat({job:job, step:array_step})
return tmp.length
}
return "_todo"
}
T_m_p.prototype.analysis_pcs_count_on_array = function(props){ //
if(!this.array_step){return "_error"}
var has_step = has_steps({job:this.job, pcs_step:this.pcs_step ,array_step:this.array_step}) // 有无拼版关系
if(has_step){
// arr 中 pcs数量
var tmp = GEN.getRepeat({job:job, step:array_step})
return tmp.length
}
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].odb_name
var cover_layer = laser_layers[i+1].odb_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].odb_name + "_cover"
GEN.selClearFeature()
GEN.workLayer({name:layers[0].odb_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].odb_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].odb_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_exist2 = function(props){ // 存在某某层? string
var layers = Object.keys(this.matrixInfo.matrix)
if(/string/ig.test(typeof(props))){
return layers.indexOf(props) >= 0 ? "yes" : "no"
} else {
var res = "no"
props.forEach(function(v){
if(layers.indexOf(v)>=0){
res = "yes"
}
})
return res
}
}
T_m_p.prototype.analysis_layer_exist = function(props){ // 存在某某层? string
var layers = Object.keys(this.matrixInfo.matrix)
if(/string/ig.test(typeof(props))){
return layers.indexOf(props) >= 0 ? "yes" : "no"
} else {
var res = "no"
props.forEach(function(v){
if(layers.indexOf(v)>=0){
res = "yes"
}
})
return res
}
}
T_m_p.prototype.analysis_laser_via_on_buried_hole = function(){ // via孔在埋孔上
var t = this
// 找出 镭射孔 机械孔
var laser_layers = []
var buried_hole = []
for (var key in t.matrix) {
var val = t.matrix[key]
if(val.type == "laser_drill"){
laser_layers.push(key)
} else if(val.type == "blind_drill" || val.type == "bury_drill"){
buried_hole.push(key)
}
}
var res = "no"
if(buried_hole.length>0 && laser_layers.length){ // 有机械孔 和镭射
GEN.openStep({job:t.job,name:t.pcs_step})
GEN.affectedLayer({affected:'no',mode:'all'})
try {
laser_layers.forEach(function(laser){
GEN.workLayer({name:laser,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
buried_hole.forEach(function(buried){
GEN.selRefFeat({layers:buried,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
res = "yes"
throw "yes"
}
})
})
} catch (msg) { }
GEN.closeStep()
}
return res
}
T_m_p.prototype.analysis_milling_bit_size = function(){ // todo
return "_todo"
}
T_m_p.prototype.analysis_milling_length_card = function(){ // todo
var allStep = [this.pcs_step, this.array_step]
var res = 0
var that = this;
console.log("============analysis_milling_length_card=============");
console.log("========step========:"+_.toString(allStep));
var steps = GEN.getStepList({job:this.job})
allStep.forEach(function(step){
if(steps.indexOf(step)>=0){
GEN.openStep({job:that.job,name:step})
var tmp = "length_tmp"
if(GEN.isLayerExists({job:that.job,layer:tmp})){GEN.deleteLayer({job:that.job,layer:[tmp]})}
GEN.createLayer({job:that.job,layer:tmp,conext:'misc',type:'document'})
GEN.COM("profile_to_rout,layer="+tmp+",width=1")
var feautres = GEN.getFeatures({job:that.job,step:step,layer:tmp,units:"mm"})
fs.writeFile("/home/samba/tmp/tmp.js", _.toString(feautres))
// 根据feautres 算出周长
var milling = Object.keys(feautres).reduce(function(a,b){
var value = feautres[b]
if (value.type=="line"){
length = Math.sqrt((Number(value.xe)-Number(value.xs))*(Number(value.xe)-Number(value.xs)) + (Number(value.ye)-Number(value.ys))*(Number(value.ye)-Number(value.ys)))
a += length
} else if (value.type=="arc") {
a += arcLength(Number(value.xs),Number(value.ys),Number(value.xe),Number(value.ye),Number(value.xc),Number(value.yc))
}
return a
}, 0)
console.log("========milling:"+milling);
res += milling
console.log("========res:"+res);
GEN.deleteLayer({job:that.job,layer:[tmp]})
}
})
res = res/1000
return res.toFixed(3)
}
T_m_p.prototype.analysis_milling_length_array = function(){ // todo
if(!this.array_step){return "_error"}
GEN.openStep({job:this.job,name:this.array_step})
var tmp = "length_tmp"
GEN.COM("profile_to_rout,layer="+tmp+",width=1")
var feautres = GEN.getFeatures({job:this.job,step:this.array_step,layer:tmp,units:"mm"})
// 根据feautres 算出周长
var milling = Object.keys(feautres).reduce(function(a,b){
var value = feautres[b]
if (value.type=="line"){
length = Math.sqrt((value.xe-value.xs)*(value.xe-value.xs) + (value.ye-value.ys)*(value.ye-value.ys))
a += length
} else if (value.type=="arc") {
a += arcLength(Number(value.xs),Number(value.ys),Number(value.xe),Number(value.ye),Number(value.xc),Number(value.yc))
}
return a
}, 0)
GEN.closeStep()
milling = milling/1000
return milling.toFixed(3)
}
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){
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_gold_finger = function(){ //
if(!ALL.gold_fingers){return "no"}
return ALL.gold_fingers.length > 0 ? "yes" : "no"
}
T_m_p.prototype.analysis_glod_finger_area = function(){ //
if(ALL.gold_fingers.length > 0){
GEN.openStep({job:this.job, name:this.pcs_step})
var gold_finger_area = {}
var res = 0;
ALL.gold_fingers.forEach(function(item){
var tmp = GEN.copperArea({layer1:item.name}).percent
res += Number(tmp)
// var tmp = GEN.copperArea({layer1:item.name}).percent + "%"
// var key = item.type == "top" ? "sf_area_gold_area_front" : "sf_area_gold_area_back"
// gold_finger_area[key] = tmp
})
GEN.closeStep()
if(res){
return String(res.toFixed(4)) + "%"
}
}
return "_todo"
}
T_m_p.prototype.analysis_ATS_sm_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]) ? "FRONT1" : "BACK1"
} else {
res = "FRONT1;BACK1"
}
return res
}
T_m_p.prototype.analysis_vc_id_print_side = function(){ // 检查文字层所在面次
var solder_mask_layers = this.matrixInfo.matrixVal.filter(function(v){return v.layer_type == "silk_screen"})
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 = "NA"
if(solder_mask_info.length == 0){
res = "NA"
} else if (solder_mask_info.length == 1) {
res = /top/ig.test(solder_mask_info[0]) ? "FRONT" : "BACK"
} else {
res = "FRONT / BACK"
}
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,name: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_c2c"] = 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_sm_width = symbolInfo_solder["min_width"]}
if(symbolInfo_solder["min_length"]){res[layer.signalL].min_smd_sm_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 = Number(res[0]), num2 = Number(res[1])
if(num1 > num2){
var tmp = num2
num2 = num1
num1 = tmp
}
if(a.width == "N/A"){
a.width = num1
a.length = num2
return a
}
if(num2 < a.length){
a.width = num1
a.length = num2
}else if(num2 == a.length && a.width > num1){
a.width = num1
a.length = num2
}
}
return a
},{width:"N/A",length:"N/A"})
return {
min_width:symbols.width,
min_length:symbols.length
}
}
function smdPitch(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: "smdPitch",
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\\;SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf && 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:"smd_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})
// 获取最小smd间距
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 createChklistAndRun(par) {
var checkLayers = par.layers
var items = par.items
GEN.createChklist({ // 创建checklist
chklist: oChecklistName,
items: items
})
GEN.chklistShow({
chklist: oChecklistName
})
GEN.affectedLayer({
affected: "yes",
layer: checkLayers,
clear_before: "yes"
})
items.forEach(function(v){
GEN.chklistRun({
chklist: oChecklistName,
nact: v.nact,
area: 'profile'
})
})
}
function analysisChkAttr(par) {
var layers = par.layers;
var hash = {};
var info = par.info;
var job = par.job;
var oChecklistName = par.oChecklistName
layers.forEach(function (v) {
saveMeans({job:job,step:par.step,chklist:oChecklistName,nact:1,layer:v,jobpath:par.jobpath})
hash[v] = {}
Object.keys(info).forEach(function (key) {
var val = info[key]
hash[v][key] = val.reduce(function (a, type) {
var tmp = GEN.getCheckAttr({
job: job,
step: par.step,
checklist: oChecklistName,
nact: 1,
attr: v + "_min_" + type
})
if (a === "N/A" && /\d+/.test(tmp)) {
tmp = Number(tmp)
a = tmp.toFixed(2)
}
if (/\d+/.test(a) && /\d+/.test(tmp) && Number(tmp) < Number(a)) {
tmp = Number(tmp)
a = tmp.toFixed(2)
}
return a
}, "N/A")
if(hash[v][key]=="N/A"){
hash[v][key] = 999
}
})
})
return hash
}
function analysisDrill(par, step){
// {"layer":"d1-2","symbol":"r3.937","start":"top","end":"isl2"}
// {"layer":"d1-2","symbol":"r35.0394","start":"top","end":"bottom"}
var job = Job.toLowerCase()
GEN.affectedLayer({affected:'no',mode:'all'})
var res = par.map(function(drill){
GEN.workLayer({name:drill.layer,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
GEN.selectByFilter({feat_types:'pad', include_syms:drill.symbol})
if(GEN.getSelectCount()>0){
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;
var res = {}
steplist.forEach(function(step){
GEN.openStep({job:job,name: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()
})
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})
// 留下pitch最小的bga 如果pitch都一样大 就跳过
var min_pitch = bgaPitch({job:job,step:step,layer:tmp_layer})
if(min_pitch){
res.min_bga_pitch = (min_pitch-0) + (symbols.size-0)
}
// 分析数据
GEN.clearLayers()
// 尺寸
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"})
GEN.selContourize()
GEN.COM("sel_cont2pad,match_tol=0,restriction=,min_size=5,max_size=100,suffix=+++")
GEN.COM("cur_atr_set,attribute=.smd")
GEN.COM("sel_change_atr,mode=add")
var ck = "tmp_chk"
if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck })}
var tmpItem = {
name: "opingsize", 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: "SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf){ tmpItem.erf = PAR.erf }
GEN.createChklist({ chklist: ck, items: [tmpItem] })
GEN.chklistShow({ chklist: ck })
GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' })
var min_smd = ["min_smd_pad"]
min_smd = min_smd.map(function(v){
return GEN.getCheckAttr({job:job,step:step,checklist:ck,attr:v,nact:1})
})
min_smd = min_smd.filter(function(v){return v!="N/A"})
if(min_smd.length == 0){
res.min_bga_openging_size = "todo" // todo
} else {
res.min_bga_openging_size = min_smd.sort(function(a,b){return a-b})[0]
}
GEN.deleteLayer({job:job,layer:[solderL_tmp,solderL_tmp+"+++"]})
}
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 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"
}
}
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:"p2p"}]})
var tmp_layer = tmp_layer2 + "_tmp"
selCopyLayer({job:job,layer:tmp_layer})
GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'});
// 获取最小bga间距
var features = GEN.getFeatures({job:job,step:step,layer:tmp_layer})
if(features && features.length){
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:num.toFixed(4),symbol:v.symbol}
})
var bga_min_pitch = tmp.sort(function(a,b){return a-b})[0]
res.bga_min_pitch = bga_min_pitch.num
// pitch 中选最小的
GEN.selClearFeature()
GEN.COM("filter_set,filter_name=popup,update_popup=no,profile=in")
GEN.COM("filter_set,filter_name=popup,update_popup=yes,slot=line,slot_by=length,min_len=0,max_len="+(bga_min_pitch.num/1000)+0.0002)
GEN.COM("filter_area_strt")
GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=none,inside_area=no,intersect_area=no")
GEN.COM("filter_reset,filter_name=popup")
}
// 所有BGA中间距最小的PAD大小
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]
// 删除非最小的
GEN.selectByFilter({include_syms:min_pad_symbol.symbol})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
res.bga_min_pitch_pad_size = min_pad_symbol.size
res.bga_min_pitch = (res.bga_min_pitch || 20) - 0 + (min_pad_symbol.size-0)
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:'cover'})
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"})
GEN.selContourize()
GEN.COM("sel_cont2pad,match_tol=0,restriction=,min_size=5,max_size=100,suffix=+++")
GEN.COM("cur_atr_set,attribute=.smd")
GEN.COM("sel_change_atr,mode=add")
var ck = "tmp_chk"
if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck })}
var tmpItem = {
name: "opingsize", 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: "SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf){ tmpItem.erf = PAR.erf }
GEN.createChklist({ chklist: ck, items: [tmpItem] })
GEN.chklistShow({ chklist: ck })
GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' })
var min_smd = ["min_smd_pad"]
min_smd = min_smd.map(function(v){
return GEN.getCheckAttr({job:job,step:step,checklist:ck,attr:v,nact:1})
})
min_smd = min_smd.filter(function(v){return v!="N/A"})
if(min_smd.length == 0){
res.bga_min_pitch_openging_size = "todo" // todo
} else {
res.bga_min_pitch_openging_size = min_smd.sort(function(a,b){return a-b})[0]
}
GEN.deleteLayer({job:job,layer:[solder_layer_tmp,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:"p2p"}]})
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 res
if(features && features.length){
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)
})
res = tmp.sort(function(a,b){return a-b})[0]
}
if (res) {
// 过滤掉pitch不是最小的线
GEN.COM("filter_set,filter_name=popup,update_popup=no,profile=in")
GEN.COM("filter_set,filter_name=popup,update_popup=yes,slot=line,slot_by=length,min_len=0,max_len="+(res/1000)+0.0002)
GEN.COM("filter_area_strt")
GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=none,inside_area=no,intersect_area=no")
GEN.COM("filter_reset,filter_name=popup")
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
GEN.workLayer({name:layer,display_number:1,clear_before:'yes'});
GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'touch'})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
}
GEN.deleteLayer({job:job,layer:tmp_layer})
GEN.deleteLayer({job:job,layer:tmp_layer1})
GEN.deleteLayer({job:job,layer:tmp_layer2})
// 矩阵
return res || 20.1
}
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
}
}
function has_steps(props){
var job = props.job
var pcs_step = props.pcs_step
var array_step = props.array_step
var res = GEN.getSubSteps({job:job, step:array_step})
return res.indexOf(pcs_step) >= 0
}
function unSelect(){
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'plated'}],profile:'all',operation:"unselect"})
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'via'}],profile:'all',operation:"unselect"})
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'non_plated'}],profile:'all',operation:"unselect"})
}
function mkPath(path,list) {
console.log("--path:" + path);
if(list.length){
var newPath = path + '/' + list.shift()
if(!fs.dirExists(newPath)){
fs.mkdir(newPath)
console.log("--mkdir:" + newPath);
}
return mkPath(newPath,list)
} else {return path}
}
function saveMeans(props){
var job = props.job
var step = props.step
var chklist = props.chklist
var nact = props.nact
var layer = props.layer
// 获取meas
var meas = GEN.getCheckMeas({job:job,step:step,chklist:chklist,nact:nact,layer:layer})
var basepath = props.jobpath+"/user/opcam/steps"
var respath = mkPath(basepath,[step,"chk",chklist+"_"+nact,layer])
fs.writeFile(respath+"/meas",meas.join("\n"))
fs.chmod(respath+"/meas",777)
}
// 算弧长
function arcLength(x1,y1,x2,y2,x3,y3){
var cos0 = +((x3-x1)*(x2-x3) + (y3-y1)*(y2-y3)) / (Math.pow((Math.pow(x2-x3,2) + Math.pow(y2-y3,2)),0.5) * Math.pow((Math.pow(x3-x1,2) + Math.pow(y3-y1,2)),0.5))
var tmp = Math.acos(cos0)
var sin0 = Math.sin(tmp)
var length = +Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2)) / sin0 * tmp
return length
}
\ No newline at end of file
/*
NAME:
DESCRIPTION: ;
PARAMETER:
[
{
name : 'path',
title : '资料路径',
type : 'LineEdit',
property : {tool_tip : '资料路径,必填'},
},
{
name : 'db',
title : '料号db',
type : 'LineEdit',
property : {tool_tip : '料号db,默认是genesis'},
},
{
name : 'config_path',
title : '配置地址',
type : 'LineEdit',
property : {tool_tip : '配置的路径'},
}
]
VERSION_HISTORY:
V1.00 2020-04-20 Scott Sun
1.新版本
HELP:
<html><body bgcolor="#DDECFE">
<font size="3" color="#003DB2"><p>功能简介</p></font>
<p> 客户数据导入 </p>
<br>
<font size="3" color="#003DB2"><p>参数配置</p></font>
<p> 料号 和 客户配置 </p>
<br>
<font size="3" color="#003DB2"><p>注意事项</p></font>
<p> 无 </p>
<br>
</body></html>
*/
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// 引入模块 包
console.log("=============================================>input_start");
console.log("=============================================>input_start");
console.log("=============================================>input_start");
console.log("=============================================>input_start");
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 }
});
}
}
var Status = 'ok';
var resultData = [];
var import_info = []
try {
var par = PAR;
// var db_path = db.query("",function(q){
// return q.selectValue({
// table:'pub_conf',
// field:'text_data',
// where:{path : "quote-data-upload"}
// })
// });
// if(_.isEmpty(db_path)){throw "quote-data-upload error"}
if(!par.path || par.path == "") {throw "path error"}
if(!par.hasOwnProperty("config_path") || par.config_path==""){
console.log("========================cfg");
par.config_path = "cam/input_data"
};
if(!par.hasOwnProperty("db") || par.db==""){
console.log("========================db");
par.db = "genesis"
};
var db_customer = db.query("",function(q){
return q.selectValue({
table:'pdm_job',
field:'customer_code',
where:{id : JobId}
})
});
if(_.isEmpty(db_customer)){throw "customer error"}
if(db_customer && !(/^done$/ig.test(db_customer)) && db_customer != "" ){
par.customer = db_customer
}
par.customer = par.customer[0].toUpperCase()+par.customer.slice(1).toLowerCase()
var cfg = db.query("",function(q){
return q.selectValue({
table:'pub_conf',
field:'text_data',
where:{path : par.config_path}
})
});
if (!cfg || cfg == ""){throw "cfg can not find"}
var config = eval(cfg);
if(!config.hasOwnProperty("customer")){throw "config error"}
var job = Job;
if(_.isEmpty(job)) throw "没有传入料号名!";
job = job.toLowerCase()
// 如果genesis已经存在这个料号
err = delSameJob({job:job,delSame:config.delSameJob}); if(err){throw err};
var custCfg = config.customer[par.customer]
if(!custCfg){throw "customer config error:"+par.customer}
custCfg.db = par.db || custCfg.db
var step = custCfg.step.toLowerCase()
// 获取路径下文件信息
var path = par.path
if(!fs.exists(path)){throw "path error"}
var pathInfo = fs.listDir(path + "/" + db_customer.toLowerCase(), 1)
// 判断存不存在料号文件
// var vc_position = db.query("",function(q){
// return q.selectValue({
// table:'pdm_job',
// field:'version',
// where:{id : JobId}
// })
// });
var job_file_baseName = job
// if(vc_position && vc_position != "" && !(/null/ig.test(vc_position))){
// job_file_baseName = job_file_baseName + "_" + vc_position
// }
console.log("========= ====>pathInfo:"+ _.toString(pathInfo) + " job: " + job_file_baseName)
var jobFile = pathInfo.filter(function(v){return v.baseName.toLowerCase() == job_file_baseName})
if(jobFile.length == 0){throw "job file is not exist"}
var jobFiles = [] // 记录要分析的文件
if (!jobFile[0].isDir) {
jobFiles.push(jobFile[0])
} else {
jobFiles = fs.listDir(jobFile[0].path)
}
GEN.COM("config_edit,name=iol_gbr_polygon_break,value=1,mode=user")
GEN.COM("config_edit,name=iol_fix_ill_polygon,value=yes,mode=user")
// 分析料号文件 得到料号导入信息 导入类型
var jobInfo = analyJobFiles({jobFiles:jobFiles.filter(function(v){return v.isFile}),custCfg:custCfg,config:config,job:job })
if(jobInfo.data.length == 0){throw "file error"}
var importOk = false; // 是否成功导入
if(/odb/ig.test(jobInfo.type)){ // odb导入
if(jobInfo.data.length == 1){ // 只分析到一个tgz文件 直接导入
IKM.msg("只分析到一个tgz文件 直接导入")
import_info.push({name:jobInfo.data[0].file.name, type:"odb++", date:now(),user:$.user_name})
var err = importJob({name:job,db:custCfg.db,path:jobInfo.data[0].file.path},config.delSameJob)
if(err){throw err}
} else { // 多个tgz文件 说明需要合并
console.log("==========合并的情况");
var jobs = jobInfo.data.map(function(item, i){
var path = item.file.path
var tmp_job_name = job + "_tmp_" + i
var err = importJob({name:tmp_job_name,db:custCfg.db,path:path},config.delSameJob)
import_info.push({name:item.file.name, type:"odb++", date:now(),user:$.user_name})
if(err){throw err}
return {
name:tmp_job_name,
path: path
}
})
var step_all = [];
// 分析arr_job 和 pcs_job
jobs.forEach(function(item){
var jobname = item.name
GEN.openJob({job:jobname});
var steps = GEN.getStepList({job:jobname})
steps.forEach(function(stepname){
var type = getStepType(stepname) // pcs arr
if(type == "pcs"){
step_all.unshift({
jobname: jobname,
stepname: stepname,
type: type
})
}
if(type == "arr"){
step_all.push({
jobname: jobname,
stepname: stepname,
type: type
})
}
})
})
var pcs_job_name_tmp = step_all[0].jobname
step_all = step_all.filter(function(item){
return item.jobname != pcs_job_name_tmp
})
var pcs_job = jobs.filter(function(item){
return item.name == pcs_job_name_tmp
})[0]
importJob({name:job,db:custCfg.db,path:pcs_job.path},config.delSameJob)
GEN.openJob({job:job});
step_all.forEach(function(item){
if(!GEN.isJobOpen({job:item.jobname})){ GEN.openJob({job:item.jobname})};
GEN.copyStep({ // 合并
source_job:item.jobname,
source_name:item.stepname,
dest_job:job,
dest_name:item.stepname,
});
})
jobs.forEach(function(item){
var v = item.name
if(GEN.isJobOpen({ job: v })){ GEN.closeJob({ job: v }) }
GEN.deleteJob({ job: v }); // 合并后 删除array的料号
})
}
importOk = true
}
if(/gerber/ig.test(jobInfo.type)){ // gerber导入
GEN.createJob({name:job,db:custCfg.db})
GEN.createStep({job:job,name:step})
var gerberInfo = jobInfo.data.map(function(item){
var gerberCfg = JSON.parse(JSON.stringify(item.format));
var file = item.file
gerberCfg.layer = file.name.toLowerCase().split(" ").join("-")
gerberCfg.path = file.path
gerberCfg.format = item.type
gerberCfg.job = job
gerberCfg.step = step
return gerberCfg
})
GEN.COM("input_manual_reset")
gerberInfo.forEach(function(v){
import_info.push({name:v.layer, type:"gerber274x", date:now(),user:$.user_name})
GEN.COM("input_manual_set",v)
})
GEN.COM("input_manual")
importOk = true
}
if(!importOk){throw "import error"}
// 导入结束
var matrix = GEN.getMatrix({job:job});
comp = Object.keys(matrix).filter(function(v){ // 如果有comp层 删除
return /^comp_\+_/ig.test(v)
})
if (comp.length > 0){
var tmp = GEN.getStepList({job:job})
GEN.openStep({job:job,name:tmp[0]})
GEN.COM("delete_comp")
GEN.closeStep()
}
reNameStep(job)
GEN.checkInout({job:job,mode:"out"}) // 结束保存料号 关闭料号
GEN.saveJob({ job: job });
GEN.checkInout({job:job,mode:"in"})
GEN.closeJob({job:job})
// name type date user
resultData.push({type: "info",title:"导入资料列表",detail: [{ desc:
import_info.map(function(item){
var name = item.name
var type = item.type
var date = item.date
var user = item.user
return "导入资料:"+name+", 类型:"+type+", 导入时间:"+date+", 操作用户:"+user
}).join("\n")
}] })
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 delSameJob(props){
var job = props.job
var delSame = props.delSame
console.log("======================>delsame:"+ delSame);
if(GEN.isJobExists({job:job})){
if(/^yes$/ig.test(delSame)){
if(GEN.isJobOpen({job:job})){ GEN.closeJob({job:job}) }
GEN.deleteJob({job:job})
} else {
return "job "+ job+ " exist"
}
}
}
function analyJobFiles(props){
var files = props.jobFiles;
var config = props.config;
var job = props.job;
var custCfg = props.custCfg;
var rules = custCfg.rules;
var paramsFile = files.filter(function(file){return /param|ncdrill/ig.test(file.baseName)})
var tmp_hash = {}
paramsFile.forEach(function(file){
tmp_hash[file.baseName] = (function(){
var tmparr = fs.readFile(file.path).split("\n").filter(function(v){return /^\S+\s+\S/ig.test(v)})
var tmp = {}
tmparr.map(function(v){
var arr = v.split(/\b\s+\b/)
tmp[arr[0].replace(/-/ig,"_")] = arr[1]
})
return tmp
})()
})
var fileInfo = files.reduce(function(a,file){
try {
rules.forEach(function(item){
if(item.valid({file:file, job:job})){
var format = config.formats[item.format]
var format1;
if(item.format_params){
format1 = item.format_params({params:tmp_hash})
}
if(format1){
throw {file:file,type:item.type,format:format1}
}else{
throw {file:file,type:item.type,format:format}
}
}
})
} catch (info) {
a.push(info)
}
return a
},[])
var odbfiles = fileInfo.filter(function(item){return /odb/ig.test(item.type)})
if(odbfiles.length == 0){
return {
type: "Gerber",
data: fileInfo
}
} else {
return {
type: "ODB",
data: odbfiles
}
}
}
function importJob(props,delSameJob){
var name = props.name
if (GEN.isJobExists({ job: name })) {
if (/^yes$/ig.test(delSameJob)) {
if(GEN.isJobOpen({ job: name })){ GEN.closeJob({ job: name }); }
GEN.deleteJob({ job: name });
}
else {
return "job "+name+" exist";
}
}
IKM.msg(props)
GEN.importJob(props);
}
function getStepType(step){
if(/pcs|cad|orig|pcb/ig.test(step)){
return "pcs"
}
if(/stp|arr/ig.test(step)){
return "arr"
}
return "pcs"
}
function now(){
var date = new Date()
var time = _.toString(date)
res1 = /\d{4}-\d{2}-\d{2}/.exec(time)
res2 = /\d{2}:\d{2}:\d{2}/.exec(time)
return res1 + " " +res2
}
function reNameStep(job) {
var stepList = GEN.getStepList({job:job})
var pcs = []
var arr = []
stepList.forEach(function(v){
if(v==="cad"){
pcs.unshift(v)
} else if(/pcs|cad|orig|pcb/ig.test(v)){
pcs.push(v)
} else if(/stp|arr/ig.test(v)){
arr.push(v)
}
})
pcs.forEach(function(v, i){
if (i==0 && v == "cad") {
} else {
GEN.renameStep({job:job,name:v,new_name:'cad' + (i == 0? "" : i+1)})
}
})
arr.forEach(function(v, i){
if (i==0 && v == "stp") {
} else {
GEN.renameStep({job:job,name:v,new_name:'stp' + (i == 0? "" : i+1)})
}
})
}
\ No newline at end of file
/*
NAME:
DESCRIPTION: ;
PARAMETER:
[
{
name : 'config_path',
title : '配置地址',
type : 'LineEdit',
property : {tool_tip : '配置的路径'},
}
]
VERSION_HISTORY:
V1.00 2020-04-17 Scott Sun
1.新版本
HELP:
<html><body bgcolor="#DDECFE">
<font size="3" color="#003DB2"><p>功能简介</p></font>
<p> 数据标准化 </p>
<br>
<font size="3" color="#003DB2"><p>参数配置</p></font>
<p> 客户配置 </p>
<br>
<font size="3" color="#003DB2"><p>注意事项</p></font>
<p> 无 </p>
<br>
</body></html>
*/
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// 引入模块 包
console.log("==============================================>data_format")
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 }
});
}
}
var Status = 'ok';
var resultData = [];
try {
var par = PAR;
if(!par.hasOwnProperty("config_path") || par.config_path==""){
console.log("==============cfg");
par.config_path = "cam/input_data"
};
var db_customer = db.query("",function(q){
return q.selectValue({
table:'pdm_job',
field:'customer_code',
where:{id : JobId}
})
});
if(_.isEmpty(db_customer)){throw "customer error"}
if(db_customer && !(/^done$/ig.test(db_customer)) && db_customer != "" ){
par.customer = db_customer
}
par.customer = par.customer[0].toUpperCase()+par.customer.slice(1).toLowerCase()
var cfg = db.query("",function(q){
return q.selectValue({
table:'pub_conf',
field:'text_data',
where:{path : par.config_path}
})
});
if (!cfg || cfg == ""){throw "cfg can not find"}
var config = eval(cfg)
var job = Job;
if(_.isEmpty(job)) throw "没有传入料号名!";
job = job.toLowerCase()
var custCfg = config.customer[par.customer] // 获取客户配置
if(!custCfg){throw "config error"}
// 料号验证
if(!GEN.isJobExists({job:job})){ throw "job "+ job+ " is not exist" }
if(!GEN.isJobOpen({job:job})){GEN.openJob({job:job})}
if(GEN.checkInout({job:job,mode:"test"}) != 0 && mode != "develop"){ throw "the job check" }
console.log("Checkout====== ========================>")
GEN.checkInout({job:job,mode:"out"});
console.log("Checkout success==============================>")
var profileRule = []
if(custCfg.hasOwnProperty("mergerule")){
var mergeRule = custCfg.mergerule
if(mergeRule.drill){
if (mergeRule.drill_second){
var matrix = GEN.getMatrix({job:job})
var layers = Object.keys(matrix)
var is_second = false
layers.forEach(function(layer){
mergeRule.drill.forEach(function(item){
var reg = new RegExp(item.orig_rule,"ig")
if(reg.test(layer)){is_second = true}
})
})
if(!is_second){
mergeRule.drill = mergeRule.drill_second
}
}
if(/string/ig.test(typeof(mergeRule.drill[0]))){ // drill层 计算
var drill_layers = []
var matrix = GEN.getMatrix({job:job})
// 计算最大值
var layers = Object.keys(matrix)
var maxnum = []
layers.forEach(function(v){
var hasrule
mergeRule.drill.forEach(function(rule){
var reg = new RegExp(rule,"ig")
if(reg.test(v)){hasrule = rule}
})
if(hasrule){
var reg = new RegExp(hasrule,"ig")
var tmp = reg.exec(v)
var num1 = Number(tmp[1])
var num2 = Number(tmp[2])
if(num1==1){
drill_layers.push({num1:num1,num2:num2,layer:v})
}
maxnum.push(num1)
maxnum.push(num2)
}
})
var max = maxnum.sort(function(a,b){return b-a})[0]
var drill_layer = drill_layers.filter(function(v){return v.num2 == max})
if(drill_layer.length){
drill_layer = drill_layer[0].layer
GEN.COM("matrix_rename_layer",{job:job,matrix:"matrix",layer:drill_layer,new_name:"drill"})
}
}else if(/object/ig.test(typeof(mergeRule.drill[0]))){
var matrix = GEN.getMatrix({job:job})
// 计算最大值
var layers = Object.keys(matrix)
var tmp_step = GEN.getStepList({job:job})
GEN.openStep({job:job,name:tmp_step[0]})
layers.forEach(function(layer){
var tmp = mergeRule.drill.filter(function(item){
var reg = new RegExp(item.orig_rule,"ig")
return reg.test(layer)
})
if(tmp.length){
tmp = tmp[0]
GEN.workLayer({name:layer,display_number:2,clear_before:'yes'})
if(tmp.drill_type){
GEN.COM("cur_atr_set,attribute=.drill,option="+tmp.drill_type)
GEN.COM("sel_change_atr,mode=add")
}
GEN.selCopyOther({dest:'layer_name',target_layer:'drill',invert:'no',dx:0,dy:0,size:0})
GEN.workLayer({name:"drill",display_number:2,clear_before:'yes'})
GEN.COM("chklist_single,action=valor_dfm_nfpr,show=yes")
GEN.COM("chklist_cupd,chklist=valor_dfm_nfpr,nact=1,params=((pp_layer=.affected)(pp_delete=Duplicate)(pp_work=Features)(pp_drill=PTH\;NPTH\;Via\;PTH - Pressfit\;Via - Laser\;Via - Photo)(pp_non_drilled=Yes)(pp_in_selected=All)(pp_remove_mark=Remove)),mode=regular")
GEN.COM("chklist_run,chklist=valor_dfm_nfpr,nact=1,area=global")
GEN.deleteLayer({job:job,layer:["drill+++"]})
}
})
GEN.closeStep()
}
}
if(mergeRule.laser){
var newdrills = mergeLaser({job:job, mergeRule:mergeRule.laser})
var tmp_step = GEN.getStepList({job:job})
GEN.openStep({job:job,name:tmp_step[0]})
newdrills.forEach(function(v){
GEN.workLayer({name:v,display_number:2,clear_before:'yes'})
GEN.COM("chklist_single,action=valor_dfm_nfpr,show=yes")
GEN.COM("chklist_cupd,chklist=valor_dfm_nfpr,nact=1,params=((pp_layer=.affected)(pp_delete=Duplicate)(pp_work=Features)(pp_drill=PTH\;NPTH\;Via\;PTH - Pressfit\;Via - Laser\;Via - Photo)(pp_non_drilled=Yes)(pp_in_selected=All)(pp_remove_mark=Remove)),mode=regular")
GEN.COM("chklist_run,chklist=valor_dfm_nfpr,nact=1,area=global")
GEN.deleteLayer({job:job,layer:["drill+++"]})
})
GEN.deleteLayer({job:job,layer:newdrills.map(function(v){return v + "+++"})})
GEN.closeStep()
}
if(mergeRule.profile){
profileRule = mergeRule.profile
}
}
// start martix_tl_name
console.log("get matrix ====== ======== job:" + job);
var matrix = GEN.getMatrix({job:job});
console.log("=========matrix:" + _.toString(matrix));
console.log("matrix add tl_name :");
var tl_name_matrix = tlNameMatrix({matrix:matrix,tl_name:custCfg.tl_name}) // 给matrix信息添加tl_name
console.log("tl_name add end:");
var format_cfg = config.data_format // 拿到数据标准化配置
// 排序和设属性
var ret = sortLayer({job:job, rule:format_cfg, matrix:tl_name_matrix})
if(ret.err){throw err}
var after_sort_matrix = ret.sortNames
// 设置钻孔
err = setDrill({job:job, matrix:after_sort_matrix})
if(err){throw err}
// 改名
err = reName({job:job, matrix:after_sort_matrix, cfg:format_cfg})
if(err){throw err}
var tmp_matrix = GEN.getMatrix({job:job})
// 钻孔名称再次更改
var ftdrill_layer = Object.keys(tmp_matrix).filter(function(v){
return tmp_matrix[v].layer_type=="drill" && tmp_matrix[v].context=="board"
})
var hasMainDrill = Boolean(ftdrill_layer.indexOf("ftdrill") >= 0)
var layer_count = GEN.getLayerCount({job:job})
ftdrill_layer.forEach(function(v){
if(/(\d+)-(\d+)/.test(v)){
var tmp = /(\d+)-(\d+)/.exec(v)
var num1 = Number(tmp[1])
var num2 = Number(tmp[2])
var chabie = num2 - num1
if(num1 == 1 && num2 == layer_count && !hasMainDrill){
GEN.renameLayer({job:job,layer:v,new_name:"ftdrill"})
if (ftdrill_layer[ftdrill_layer.length-1]!= v){
GEN.matrixMoveRow({ job:job,layer:"ftdrill",after:ftdrill_layer[ftdrill_layer.length-1] })
}
} else if(chabie>1 && chabie < layer_count - 1){
// 改名
GEN.renameLayer({job:job,layer:v,new_name:v.substr(0,v.length-1)})
}
}
})
var all_layer = Object.keys(tmp_matrix)
// 没有outline层
if(all_layer.indexOf("outline") >= 0) { profileRule.unshift("outline")}
if(profileRule){
// 判断有没有profile
var board_layer = all_layer.filter(function(v){
return tmp_matrix[v].context == "board"
})
var tmp_step = GEN.getStepList({job:job})[0]
GEN.openStep({job:job, name:tmp_step})
var now_profile = GEN.getProfile({job:job, step:tmp_step})
if(now_profile.match(/\n/ig).length == 1){ // 如果没有profile
createOutline({job:job, step:tmp_step, matrix: tmp_matrix, profileRule:profileRule})
var hasProfile = GEN.getProfile({job:job, step:tmp_step})
if(hasProfile.match(/\n/ig).length == 1){
throw "创建profile失败"
}
} else {
GEN.affectedLayer({affected:'yes',layer: board_layer, clear_before:"yes"})
GEN.selectByFilter({profile:"out"})
if(GEN.getSelectCount() > 0){
GEN.selDelete()
}
}
}
console.log("_______format_end_________wait_for_save:");
// end
GEN.checkInout({job:job,mode:"out"}) // 结束保存料号 关闭料号
GEN.saveJob({ job: job });
GEN.checkInout({job:job,mode:"in"})
GEN.closeJob({job:job})
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 tlNameMatrix(props){ // 设置标准名
var matrix = props.matrix
var tlname_rules = []
props.tl_name.forEach(function(item){
if(typeof item.orig_name == "string"){
tlname_rules.push(item)
} else {
item.orig_name.forEach(function(name2){
tlname_rules.push({
orig_name: name2,
tl_name: item.tl_name
})
})
}
})
var res = Object.keys(matrix).map(function(key){ // 将matrix信息添加tl_name 如果没有tl_name 就返回原信息
var val = matrix[key]
if(val.hasOwnProperty("tl_name")){delete val.tl_name}
var tlRule = tlname_rules.filter(function(rule){
if(rule.orig_name === key){return true}
var reg = new RegExp(rule.orig_name,"ig")
return reg.test(key)
})
if(tlRule.length == 0){return val}
for(var i=0;i<tlRule.length;i++){
if(tlRule[i].orig_name === key){return _.assign(val,{tl_name:tlRule[0].tl_name})}
}
var reg = new RegExp(tlRule[0].orig_name,"ig")
var tmp = reg.exec(key)
if(tmp && tmp.length){
var replaceArr = tmp.slice(1)
var tl_name = tlRule[0].tl_name
var params = {}
for(var i = 0; i<replaceArr.length;i++){
params["$"+(i+1)] = replaceArr[i]
}
replaceArr.forEach(function(v,i){
tl_name = tl_name.replace("($"+(i+1)+")",v)
})
tl_name = replaceTlName(tl_name)
function replaceTlName(name){
var tmp = /(\([^)]*\))/ig.exec(name)
if(!tmp){ return name }
var param_arr = tmp[1].match(/\$\d+/ig)
var newname = tmp[1]
param_arr.forEach(function(v){
newname = newname.replace(new RegExp("\\"+v,"ig"), params[v])
})
newname = name.replace(tmp[1],eval(newname))
return replaceTlName(newname)
}
return _.assign(val,{tl_name:tl_name})
}else {
return _.assign(val,{tl_name:tlRule[0].tl_name})
}
})
return res
}
function sortLayer(props){ // 排序方法 {job:要排序的料号, rule: {要改名的规则}
var job = props.job
var matrix = GEN.getMatrix({job:job})
var tl_matrix = props.matrix
var matrixName = Object.keys(matrix).sort(function(a,b){return matrix[a].row - matrix[b].row})
var matrixFirst = matrixName[0]; // 记录matrix中第一位
var sortNames = [];
var miscName = tl_matrix.filter(function(value){ // 找出需要排序的名称列表
var flag = true;
if (!value.tl_name || value.tl_name == ""){return true}
var tl_name = value.tl_name
props.rule.forEach(function(item,i){
var evalReg = "/"+item.tl_name+"/ig.test(tl_name)";
if(tl_name == item.tl_name || eval(evalReg)){
flag = false;
if(tl_name === item.tl_name){
var _item = JSON.parse(JSON.stringify(item));
_item.value = i;
_item.name = value.name
_item.rule = item.tl_name
sortNames.push(_item);
} else {
var _item = JSON.parse(JSON.stringify(item));
_item.value = i;
var str = "/"+ item.tl_name +"/ig.exec(tl_name)"
_item.value2 = eval(str).pop() - 0;
_item.name = value.name
_item.rule = item.tl_name
_item.tl_name = tl_name;
sortNames.push(_item);
}
}
});
return flag;
}).map(function(v){return v.name})
miscName.forEach(function(n){
if(matrix[n].context == 'board'){
GEN.matrixLayerAttr({job:job,layer:n,context:'misc'})
}
})
sortNames = sortNames.sort(function(a,b){
return a.value - b.value || a.value2 - b.value2
})
// 排序
if(sortNames.length){
if(sortNames[0].name !== matrixFirst) { // 如果第一位和matrix中第一位不同,先把第一位插入到最前面
GEN.matrixMoveRow({ job:job,layer:sortNames[0].name,before:matrixFirst })
}
sortNames.forEach(function(v,i,arr){
if(i !== 0){
GEN.matrixMoveRow({ job:job,layer:v.name,after:arr[i-1].name })
}
GEN.matrixLayerAttr(_.assign({job:job,layer:v.name},v.attr));
})
}
return {
sortNames:sortNames
}
}
function setDrill(props){ // 设置钻孔
var job = props.job
var matrix = props.matrix
// 获取所有的钻孔层
var drillLayer =matrix.filter(function(v){
return (v.attr.type == "drill" || v.attr.type == "rout") && v.attr.context == "board"
})
// 获取所有single层
var signalLayer =matrix.filter(function(v){
return v.attr.type == "signal" && v.attr.context == "board"
})
console.log("=================>setdrill:drillLayer:" + _.toString(drillLayer));
console.log("=================>setdrill:signalLayer:" + _.toString(signalLayer));
var layerCount = GEN.getLayerCount({job:job})
// findSignal 根据传入的数字找到对应的signal层 如 1 => top ; 2 => layer_2
function findSignal(num){
console.log(num)
return signalLayer[Number(num-1)].name
}
function doDrill(drills){ // 分析钻孔层
return drills.map(function(v){
if(v.tl_name == "drill" || v.tl_name=="rout" || v.tl_name=="outline"){
return {start:findSignal(1), end:findSignal(layerCount), layer:v.name}
} else {
var tmp = /(\d+)-(\d+)/ig.exec(v.tl_name);
if(tmp){
var start = findSignal(tmp[1]);
var end = findSignal(tmp[2]);
return {start:start, end:end, layer:v.name}
} else {
return 0;
}
}
})
}
var drillSetList = doDrill(drillLayer); // 分析得到钻孔设置结果
drillSetList = drillSetList.filter(function(v){return v!==0})
drillSetList.forEach(function(v){
GEN.matrixLayerDrill({job:job,layer:v.layer,start:v.start ,end:v.end})
})
}
function reName(props) { // 改名 par{job:要改名的料号, rule: {要改名的规则}
var job = props.job
var matrix = props.matrix
var cfg = props.cfg
matrix = matrix.filter(function(v){return v.name != v.new_name})
var rename_list = matrix.map(function(item){
var new_name;
var tl_name = item.tl_name
var rule = item.rule
if(rule === tl_name){
new_name = item.new_name
} else {
var reg = new RegExp(rule,"ig")
var tmp = reg.exec(tl_name)
if(!tmp){return undefined}
var replaceArr = tmp.slice(1)
new_name = item.new_name
var params = {}
for(var i = 0; i<replaceArr.length;i++){
params["$"+(i+1)] = replaceArr[i]
}
replaceArr.forEach(function(v,i){
tl_name = tl_name.replace("($"+(i+1)+")",v)
})
new_name = replaceTlName(new_name)
function replaceTlName(name){
var tmp = /(\([^)]*\))/ig.exec(name)
if(!tmp){ return name }
var param_arr = tmp[1].match(/\$\d+/ig)
var newname = tmp[1]
param_arr.forEach(function(v){
newname = newname.replace(new RegExp("\\"+v,"ig"), params[v])
})
newname = name.replace(tmp[1],eval(newname))
return replaceTlName(newname)
}
}
return {
orig_name: item.name,
new_name: new_name
}
})
rename_list = rename_list.filter(function(v){
var flag = true
if(!v){flag = false}
if(!v.orig_name || !v.new_name ){flag = false}
return flag
})
rename_list.forEach(function(v){
if(v.orig_name !== v.new_name && !GEN.isLayerExists({job:job, layer: v.new_name})){
GEN.renameLayer({job:job,layer:v.orig_name,new_name:v.new_name})
}
});
// 最后 如果第一个 最后一个不是top bottom 就手动修改
var afterMatrix = GEN.getMatrix({job:job})
var signals = Object.keys(afterMatrix).filter(function(v){return afterMatrix[v].layer_type=="signal" && afterMatrix[v].context=="board"})
signals = signals.sort(function(a,b){return afterMatrix[a].row - afterMatrix[b].row})
var topSignal = signals[0]
var botSignal = signals[signals.length -1]
if(topSignal !== "top"){
GEN.renameLayer({job:job,layer:topSignal,new_name:"top"})
}
if(botSignal !== "bottom"){
GEN.renameLayer({job:job,layer:botSignal,new_name:"bottom"})
}
}
function mergeLaser(props){ // 合并钻孔
if(!props.mergeRule){return}
var mergeRuleRegs = props.mergeRule.regs
var mergeTlname = props.mergeRule.tl_name
var newdrills = []
var merge_info = {}
var regs = mergeRuleRegs
var job = props.job;
var step = GEN.getStepList({job:job})[0];
var maxDrill = {name:"",value:0};
function getDrl(str, r){
var reg = new RegExp(r,"ig")
var num = reg.exec(str); // 匹配出 num-num
var tmp = [];
for(var i = Number(num[1]);i<num[2];i++){
if(i == 1){
maxDrill = Number(num[2]) > maxDrill.value? {name:str,value:Number(num[2])} : maxDrill;
}
var layername = mergeTlname.replace("($1)", i)
layername = layername.replace("($2)", i+1)
tmp.push(layername);
}
return tmp;
}
var matrix = GEN.getMatrix({job:job});
GEN.openStep({job : job,name:step});
for(var key in matrix){
var val = matrix[key];
var tmpregs = regs.filter(function(v){
var reg = new RegExp(v,"ig")
return reg.test(val.name)
})
if(tmpregs.length > 0){
var reg = tmpregs[0]
var mergeTo = getDrl(val.name, reg) // 要合并到的地方
merge_info[val.name] = mergeTo
mergeTo.forEach(function(layerName){
if(GEN.isLayerExists({job : job ,layer:layerName.toLowerCase()}) && newdrills.indexOf(layerName.toLowerCase()) < 0){
GEN.deleteLayer({job:job, layer:layerName.toLowerCase()})
}
if(!GEN.isLayerExists({job : job ,layer:layerName.toLowerCase()})){
GEN.createLayer({job:job,layer:layerName.toLowerCase(),conext:'board',type:val.layer_type});
newdrills.push(layerName.toLowerCase())
}
GEN.workLayer({name:layerName.toLowerCase(),display_number:1,clear_before:'yes'});
GEN.copyLayer({source_job:job ,mode:'append',source_step:step,source_layer:val.name,dest_layer:layerName.toLowerCase()});
})
}
}
GEN.affectedLayer({affected:"no",mode:"all"});
GEN.clearLayers();
GEN.closeStep();
return newdrills
}
function createOutline(props){
var profileRule = props.profileRule
console.log("----profileRule------->:" + _.toString(profileRule));
var job = props.job
var step = props.step
var matrix = props.matrix
var outlines = Object.keys(matrix).filter(function(v){
var flag = false
profileRule.forEach(function(rule){
var reg = new RegExp(rule,"ig")
if(reg.test(v)){
flag = true
}
})
return flag
})
console.log("----outlines------->:" + _.toString(outlines));
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){
for(var i =0;i<outlines.length;i++){
tmp_outline = outlines[i]
if(cl(tmp_outline)) {
return true
}else{
continue
}
}
} 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"})
var bk = l + "_bk"
selCopyLayer({job:job,layer:bk})
GEN.workLayer({name:bk,display_number:2,clear_before:"yes"})
l = bk
GEN.selectByFilter({feat_types:"line\;arc"})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
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")
GEN.selectByFilter({feat_types:"surface"})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
GEN.selContourize()
GEN.selectByFilter({feat_types:"surface"})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
var tmp_layer = l+"+++"
GEN.selRefFeat({layers:drill_layer[0],use:'filter',mode:'touch'})
if(GEN.getSelectCount() > 0){
var tmp_outline2 = l + "_tmp"
selCopyLayer({job:job,layer:tmp_outline2})
GEN.workLayer({name:l,display_number:2,clear_before:"yes"})
GEN.selAllFeat()
GEN.selDelete()
GEN.workLayer({name:tmp_outline2,display_number:2,clear_before:"yes"})
GEN.COM("sel_clean_holes,max_size=200,clean_mode=x_and_y")
GEN.COM("sel_surf2outline,width=1")
GEN.selAllFeat()
selCopyLayer({job:job,layer:l})
GEN.workLayer({name:l,display_number:2,clear_before:"yes"})
GEN.selClearFeature()
GEN.selCreateProfile()
GEN.selectByFilter({profile:"in"})
if(GEN.getSelectCount()> 0){GEN.selDelete()}
GEN.deleteLayer({job:job, layer:tmp_layer})
GEN.deleteLayer({job:job, layer:tmp_outline2})
if(GEN.isLayerExists({job:job,layer:"outline"})){GEN.deleteLayer({job:job,layer:"outline"})}
GEN.renameLayer({job:job, layer:l,new_name:'outline'})
return true
}
GEN.deleteLayer({job:job, layer:tmp_layer})
return false
}
}
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})
}
\ No newline at end of file
/*
NAME:
DESCRIPTION: 客户数据分析
PARAMETER:
[
{
name : 'pcs_step',
title : 'pcsStep名',
type : 'LineEdit',
property : {tool_tip : 'pcs step名,默认是cad'}
},
{
name : 'cam_type',
title : 'cam_type',
type : 'LineEdit',
property : {tool_tip : 'cam_type'}
},
{
name : 'vc_src_01005_pad_result',
title : 'vc_src_01005_pad_result',
type : 'LineEdit',
property : {tool_tip : 'vc_src_01005_pad_result'}
},
{
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:'是否自动保存料号开关'
}
},
{
name : 'export_path',
title : '导出路径',
type : 'LineEdit',
property : {tool_tip : '导出路径'}
},
{
name : 'export_mode',
title : '导出模式',
type : 'RadioBox',
property : {
item_list:[
{name:'tar_gzip',text:'tar_gzip'},
{name:'tar',text:'tar'},
{name:'xml',text:'xml'},
{name:'directory',text:'directory'},
],
tool_tip:'导出模式'
}
},
{
name : 'export_submode',
title : '导出方式',
type : 'RadioBox',
property : {
item_list:[
{name:'full',text:'full'},
{name:'partial',text:'partial'},
],
tool_tip:'导出方式'
}
}
]
VERSION_HISTORY:
V1.00 2020 3-30 Scott
HELP:
<html><body bgcolor="#DDECFE">
<font size="3" color="#003DB2"><p>功能简介</p></font>
<p> 客户数据分析</p>
<br>
<font size="3" color="#003DB2"><p>参数配置</p></font>
<p> 客户参数 </p>
<font size="3" color="#003DB2"><p>注意事项</p></font>
<p> ● 无 </p>
<br>
</body></html>
*/
// 引入模块 包
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 }
});
}
}
var Status = 'ok';
var resultData = [];
var ALL = {}
var Omatrix = {};
try {
console.log("=============================================>anaysis_start");
var par = PAR;
var vc_src_01005_pad_result = par.vc_src_01005_pad_result
if(vc_src_01005_pad_result == ""){
vc_src_01005_pad_result = ".pth_pad"
}
if(par.erf == ""){delete PAR.erf}
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})
_.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.odb_name,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
GEN.selAllFeat()
if(GEN.getSelectCount()>0){
unSelect()
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.odb_name,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
var tmp_layer = v.drl_start + "tmp"
GEN.workLayer({name:v.drl_start,display_number:2,clear_before:'yes'})
GEN.selCopyOther({dest:'layer_name',target_layer:tmp_layer,invert:'no',dx:0,dy:0,size:0})
GEN.workLayer({name:tmp_layer,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:v.odb_name,use:'filter',mode:'cover'})
if(GEN.getSelectCount()> 0){GEN.selDelete()}
GEN.workLayer({name:v.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
unSelect()
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){
unSelect()
if(GEN.getSelectCount() > 0){
GEN.COM("cur_atr_set,attribute=.drill,option=non_plated")
GEN.COM("sel_change_atr,mode=add")
}
}
GEN.deleteLayer({job:job,layer:[tmp_layer]})
}
}
})
GEN.clearLayers()
// * new 钻孔叠构
var cam_drill_structure = []
var stack_drills = _.values(matrix).filter(function(item){
return item.layer_type == "drill" && item.context == "board"
})
var layerCount = GEN.getLayerCount({job:job})
stack_drills.forEach(function(drill){
GEN.clearLayers()
GEN.selClearFeature()
var drill_info = {}
var drl_start_num = drill.drl_start_num -0
var drl_end_num = drill.drl_end_num-0
drill_info.drl_start_num = drl_start_num
drill_info.drl_end_num = drl_end_num
var drl_side = "None"
if(layerCount/2 >= drl_start_num){
drl_side = "Top"
} else {
drl_side = "Bot"
}
drill_info.drl_side = drl_side
var drl_filler = "None"
if(drill.type == "laser_drill"){
drill_info.drl_type = "Laser"
drill_info.drl_name = "Laser" + drl_start_num + "-" + drl_end_num
drill_info.drl_tech = "LDD"
// 计算此层的理论 top bot
if(drl_side == "Top"){
if((drl_start_num-1)==0){ drl_filler = "None" }
else {
var top_l = "ftdrill" + (drl_start_num-1) + "-" + (drl_end_num-1) + "l"
if(GEN.isLayerExists({job:job, layer:top_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:top_l,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:drill.odb_name,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drl_filler="Via Filling"
}
}
}
var bot_l = "ftdrill" + (drl_start_num+1) + "-" + (drl_end_num+1) + "l"
if(GEN.isLayerExists({job:job, layer:bot_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:bot_l,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_overlap = "Yes"
} else {
drill_info.drl_overlap = "No"
}
}else{ drill_info.drl_overlap = "No" }
}else if (drl_side == "Bot"){
if((drl_end_num-layerCount)==0){ drl_filler = "None" }
else {
var top_l = "ftdrill" + (drl_start_num+1) + "-" + (drl_end_num+1) + "l"
if(GEN.isLayerExists({job:job, layer:top_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:top_l,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:drill.odb_name,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drl_filler="Via Filling"
}
}
}
var bot_l = "ftdrill" + (drl_start_num-1) + "-" + (drl_end_num-1) + "l"
if(GEN.isLayerExists({job:job, layer:bot_l})){
GEN.clearLayers()
GEN.selClearFeature()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selRefFeat({layers:bot_l,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_overlap = "Yes"
}else {
drill_info.drl_overlap = "No"
}
}else{ drill_info.drl_overlap = "No" }
}
} else {
GEN.clearLayers()
GEN.workLayer({name:drill.odb_name,display_number:2,clear_before:'yes'})
GEN.selectByFilter({attribute:[{attribute:".drill",option:"plated"}]})
if(GEN.getSelectCount()>0){
GEN.selClearFeature()
drill_info.drl_type = "PTH"
if(drl_end_num - drl_start_num == 1){drl_filler = "Resin Plugin"}
drill_info.drl_name = "PTH" + drl_start_num + "-" + drl_end_num
}else{
drill_info.drl_type = "NPTH"
drill_info.drl_name = "NPTH" + drl_start_num + "-" + drl_end_num
}
}
drill_info.drl_filler = drl_filler
drill_info.drl_zones = "{A}"
cam_drill_structure.push(drill_info)
})
var is_via_filling = cam_drill_structure.filter(function(v){return v.drl_filler == "Via Filling"})
if(is_via_filling.length>0){
cam_drill_structure = cam_drill_structure.map(function(item){
if(item.drl_type=="Laser" && item.drl_filler=="None"){
item.drl_filler = "Via Filling"
}
return item
})
}
save_job_info({
jobid: JobId,
jobinfohash: {cam_drill_structure: JSON.stringify(cam_drill_structure)}
})
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})
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})
var hasProfile = GEN.getProfile({job:job, step:pcs_step})
if(hasProfile.match(/\n/ig).length == 1){
throw "创建profile失败"
} else {
GEN.affectedLayer({affected:'yes',mode:'all'})
GEN.selectByFilter({profile:"out"})
if(GEN.getSelectCount() > 0){
GEN.selDelete()
}
}
} else {
GEN.affectedLayer({affected:'yes',mode:'all'})
GEN.selectByFilter({profile:"out"})
if(GEN.getSelectCount() > 0){
GEN.selDelete()
}
}
GEN.closeStep()
// * profile 和 拼版
var pandle_step = step_list.map(function(v){
var type = "unknow";
if(/^cad|^pcs/ig.test(v)){
type = "pcs"
} else if (/^arr|^stp/ig.test(v)) {
type = "array"
}
var panel_info = {job_id:JobId,step_name:v,step_type:type}
GEN.openStep({job:job,name:v})
GEN.clearLayers()
GEN.selClearFeature()
var profileLimits = GEN.getProfileLimits({job:job,step:v,units:"mm"})
if(profileLimits){
panel_info.size_x = Number(profileLimits.xsize).toFixed(3)
panel_info.size_y = Number(profileLimits.ysize).toFixed(3)
}
panel_info.datum_x = 0
panel_info.datum_y = 0
panel_info.margin = {"margin_top": 0, "margin_left": 0, "margin_right": 0, "margin_bottom": 0, "allow_margin_top": 0, "allow_margin_left": 0, "allow_margin_right": 0, "allow_margin_bottom": 0}
var profile = GEN.getProfile({job:job,step:v,units:"mm"}).split("\n")
if(profile.length>=1){
var tmp = profile.slice(1)
tmp = tmp.map(function(v){
if(v[0]==="#"){v = v.slice(1)}
return v
})
panel_info.profile = tmp.join("\n")
} else {
profile = profile.map(function(v){
if(v[0]==="#"){v = v.slice(1)}
return v
})
panel_info.profile = profile.join("\n")
}
for(var key in profileLimits){
profileLimits[key] = Number(profileLimits[key])
}
panel_info.profile_limits = profileLimits
panel_info.attr_data= {}
panel_info.extra_data= {}
var repeat = GEN.getSR1({job:job,step:v,units:"mm"})
var step_repeat = {}
repeat.forEach(function(item, i){
step_repeat[String(i)] = {
x:item.xa,
y:item.ya,
dx: item.dx,dy: item.dy,
nx:item.nx,ny:item.ny,
// gapX:item.xsize,gapY:item.ysize,
step:item.step,
angle:item.angle,
mirror:item.mirror == "no" ? 0 : 1,
step_name:item.step,
step_type:/cad|pcs|card/ig.test(item.step)? "pcs" : "array",
}
})
panel_info.step_repeat = step_repeat
save_panel_info({info:panel_info, table:"pdm_job_panelizer_step"})
GEN.closeStep()
return {name:v, type:type}})
// glod_finger
var gold_fingers = Object.keys(tmp_matrix).filter(function(v){return /^enig_top$|^enig_bot$/ig.test(v)})
if(gold_fingers.length){
gold_fingers = gold_fingers.map(function(v){
var type = (v=="enig_top") ? "top" : "bot"
return {name:v, type:type}
})
}
ALL.gold_fingers = gold_fingers
GEN.closeStep()
var config = {
jobInfo: {
layer_count: ["signal","power_ground"], // Board属性的signal或者power_ground层
pcs_size_x: {api:"vc_card_size", props:"xsize"}, // card短边尺寸 // ? 保留小数
pcs_size_y: {api:"vc_card_size", props:"ysize"}, // card长边尺寸 // ? 保留小数
array_size_x: {api:"vc_array_size", props:"xsize"}, // ! array短边尺寸 需要arr_step // ? 保留小数
array_size_y: {api:"vc_array_size", props:"ysize"}, // ! array长边尺寸 需要arr_step // ? 保留小数
vc_pcs_count_on_panel: true, // array中pcs的数量 ! 需要arr_step
pcs_count_on_array: true,
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, // via孔在埋孔上时,存yes
milling_bit_size: false, // todo 检查array中pcs的最小间距值
milling_length_card: true,
milling_length_array: true,
vc_src_01005_pad_result: {api:"board_has_attr", props:vc_src_01005_pad_result}, // 本地使用 .pth_pad ats 01005_pad
ATS_technology_25dc: {api:"layer_exist", props:["bot_coverlay","top_coverlay"]}, // yes|no:存在cavity层别时存yes
ATS_technology_25dr: {api:"layer_exist", props:["bot_coverlay","top_coverlay"]}, // yes|no:存在cavity层别时存yes
// vc_src_EDGE_PLATING: true, // yes|no:检查线路外形是否存在物件,存在则存yes // !料号需要有rout层
vc_src_EDGE_PLATING: {api:"layer_exist2", props:["fab_page2"]}, // fab_page2
edge_plating_length: true, // todo 检查线路外形处物件的长度
gold_finger: false, //
glod_finger_area: false, //
ATS_sm_side: true, // top|bot|both:检查防焊层所在面次 ATS_sm_side
vc_id_print_side: true, // top|bot|both:检查文字层所在面次 vc_id_print_side
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("========================================error:");
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_tool_info = {};
var drillLayers = analysis_obj.matrixInfo.mDrills;
var pcs_steps = [par.pcs_step]
var arr_steps = [par.array_step]
drillLayers.forEach(function(item){
var layer = item.name
if(pcs_steps.length > 0){
pcs_steps.forEach(function(step){
if(!GEN.isLayerEmpty({job:job,step:step,layer:layer})){
GEN.COM("tools_set,layer="+layer+",slots=by_length")
var tool = GEN.getTool({job:job,step:step,layer:layer,units:"mm",});
if(drill_tool_info[layer]){
Object.keys(tool).forEach(function(hashkey){
if(drill_tool_info[layer][hashkey]){
if(!drill_tool_info[layer][hashkey].pcs_count){drill_tool_info[layer][hashkey].pcs_count = 0}
drill_tool_info[layer][hashkey].pcs_count += Number(tool[hashkey].count) ;
}
})
}else{
drill_tool_info[layer] = tool ;
Object.keys(tool).forEach(function(hashkey){
if(!drill_tool_info[layer][hashkey].pcs_count){drill_tool_info[layer][hashkey].pcs_count = 0}
drill_tool_info[layer][hashkey].pcs_count += Number(tool[hashkey].count) ;
})
}
}
})
}
if(arr_steps.length > 0){
arr_steps.forEach(function(step){
if(GEN.isStepExists({job:job,step:step})){
if(!GEN.isLayerEmpty({job:job,step:step,layer:layer})){
var tool = GEN.getTool({job:job,step:step,layer:layer,units:"mm"});
if(drill_tool_info[layer]){
Object.keys(tool).forEach(function(hashkey){
if(drill_tool_info[layer][hashkey]){
if(!drill_tool_info[layer][hashkey].array_count){drill_tool_info[layer][hashkey].array_count = 0}
drill_tool_info[layer][hashkey].array_count += Number(tool[hashkey].count) ;
}
})
}else{
drill_tool_info[layer] = tool ;
Object.keys(tool).forEach(function(hashkey){
if(!drill_tool_info[layer][hashkey].array_count){drill_tool_info[layer][hashkey].array_count = 0}
drill_tool_info[layer][hashkey].array_count += Number(tool[hashkey].count) ;
})
}
}
}
})
}
})
// 删除
db.query("",function(q){
return q.deleteRow({
table:'pdm_job_cam_drill',
where:{job_id:JobId}
})
});
var seq_index = 1 ;
Object.keys(drill_tool_info).forEach(function(layer){
var datalist = []
var tool_num = 1 ;
_.values(drill_tool_info[layer]).sort(function(a,b){return a.drill_size - b.drill_size}).forEach(function(item){
var layer_name = layer
var drill_type = item.type
if(matrix[layer].type == "laser_drill" && /^[^\d]+(\d+)-(\d+)[^\d]?$/.test(layer_name)){
drill_type = "laser"
var info_drilll = /^[^\d]+(\d+)-(\d+)[^\d]?$/.exec(layer_name);
layer_name = "l" + info_drilll[1] + "-" + info_drilll[2];
} else if(layer_name === "ftdrill"){
layer_name = "drill"
} else if(/^[^\d]+(\d+)-(\d+)[^\d]?$/.test(layer_name)) {
var info_drilll = /^[^\d]+(\d+)-(\d+)[^\d]?$/.exec(layer_name);
layer_name = "d" + info_drilll[1] + "-" + info_drilll[2];
}
if(matrix[layer].type == "bury_drill"){
drill_type = "via"
}
var data = {
job_id: JobId,
layer_name: layer_name,
tool_num: "T" + tool_num,
tool_flag: tool_num,
tool_type: item.shape,
drill_type:drill_type,
// drill_size : item.drill_size,
drill_slot_length: Number(item.slot_len),
finish_size : Number(item.finish_size).toFixed(3),
finish_slot_length: Number(item.slot_len),
// size_tol_lower: item.min_tol,
// size_tol_upper: item.max_tol,
pcs_count: item.pcs_count || 0,
array_count: item.array_count || 0,
seq: seq_index + tool_num/100,
attr_data: {"org_layer_name":layer}
}
datalist.push(data)
tool_num++
})
seq_index++
// datalist存入
datalist.forEach(function(data){
db.query("",function(q){
return q.insertRow({
table:'pdm_job_cam_drill',
data:data
})
});
})
})
console.log("=============================> 6 set smd bga")
var allStep = GEN.getStepList({job:job})
allStep.forEach(function(step){
GEN.openStep({job:job,name:step})
GEN.affectedLayer({affected:'no',mode:'all'})
GEN.clearLayers()
if(GEN.GEN_TYPE == "genesis"){
GEN.COM("chklist_single,action=valor_cleanup_set_smd,show=yes")
GEN.COM("chklist_cupd,chklist=valor_cleanup_set_smd,nact=1,params=((pp_layer=.type=signal|mixed&side=top|bottom)(pp_drill=No)(pp_rotate=No)(pp_ignore_covered=Yes)(pp_sm=No)(pp_types=Square\;Rect\;Oval)(pp_other=)(pp_delete=No)),mode=regular")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("chklist_close,chklist=valor_cleanup_set_smd,mode=hide")
}else{
GEN.COM("chklist_single,show=yes,action=valor_cleanup_set_smd")
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")
GEN.COM("get_user_name")
GEN.COM("get_job_path,job="+job)
GEN.COM("disp_on")
GEN.COM("origin_on")
GEN.COM("chklist_cnf_act,chklist=valor_cleanup_set_smd,nact=1,cnf=no")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("skip_next_pre_hook")
GEN.COM("chklist_run,chklist=valor_cleanup_set_smd,nact=1,area=profile")
GEN.COM("get_user_name")
GEN.COM("skip_current_command")
GEN.COM("disp_on")
GEN.COM("origin_on")
GEN.COM("show_tab,tab=Checklists,show=no")
}
// top bottom 层smd排除掉 r\d开头的圆形smd // 与开窗touch 碰不到的删除属性
analysis_obj.matrixInfo.mOuters.forEach(function(item){
var layer = item.signalL
var oping_layer = layer.solderL
GEN.workLayer({name:layer,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
var symbols_tmp = GEN.getLayerSymsHist({job:job,step:step,layer:layer})
var syms = Object.keys(symbols_tmp)
var filter_syms = syms.filter(function(item){
if(/^rect(\d+\.\d+|\d+)x(\d+\.\d+|\d+)/ig.test(item)){
var res = /^rect(\d+\.\d+|\d+)x(\d+\.\d+|\d+)/ig.exec(item).slice(1)
var num1 = res[0], num2 = res[1]
if(num1<3 || num2<3){return true}
}
return /^r\d+/.test(item)}
)
if(filter_syms.length){
var filter_syms = filter_syms.join(";")
GEN.selectByFilter({attribute:".smd", include_syms:filter_syms, profile:"in"})
if(GEN.getSelectCount()>0){
GEN.COM("sel_delete_atr,attributes=.smd")
}
}
if(oping_layer){
GEN.COM("filter_atr_set,filter_name=popup,condition=yes,attribute=.smd")
GEN.COM("sel_ref_feat,layers="+oping_layer+",use=filter,mode=disjoint,pads_as=shape,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,include_syms=,exclude_syms=")
GEN.COM("COM filter_reset,filter_name=popup")
}
})
GEN.closeStep()
})
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;
bgaInfo = bgaAnalysis({job:job,steplist:[pcs_step],layers:analysis_obj.matrixInfo.mOuters,attr:".bga"})
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})
console.log("=============================> 13 save copperArea copper_distribution")
var copper_distribution_steplist= [pcs_step, array_step];
copper_distribution_steplist.forEach(function(step){
if(step){
GEN.openStep({ job: job, name: step })
// 铜面积 分step
var copper_percent_tmp = 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_tmp));
copper_percent_tmp.forEach(function(item){
var save_info = {
jobid: JobId,
layer: item.layer,
}
if(/^cad/ig.test(step)){
save_info.layerinfohash = {
card_copper_distribution: item.copper_percent
}
} else if(/^stp/ig.test(step)){
save_info.layerinfohash = {
array_copper_distribution: item.copper_percent
}
}
save_layerinfo(save_info)
})
GEN.closeStep()
}
})
var info = {
min_line_width: ["line","user_nor_line"],
min_line_spacing: ["l2l"],
min_line2pad: ["p2line","user_bga2nor_line","user_smd2nor_line"],
min_pad2pad: ["p2p", "smd2smd", "smd2pad","via2via","bga2pad"],
min_ar_laser:["laser_via_ar"],
min_ar_via:["via_ar"],
min_ar_pth:["pth_ar"],
min_ar_npth:["npth_ar"]
}
save_job_info({
jobid: JobId,
jobinfohash: {ATS_surface_area_base_on:"Card"}
})
var jobpath = GEN.getJobPath({job:job})
// if(GEN.GEN_TYPE == "genesis"){
// jobpath = GEN.getJobPath({job:job})
// } else {
// jobpath = "/home/local_db/server_db/jobs/"+job
// }
mkPath(jobpath,["user","opcam","steps"])
stepList.forEach(function(step){
GEN.openStep({ job: job, name: step })
// 曝光
analysis_obj.matrixInfo.mOuters.forEach(function(item){
if(ALL.gold_fingers.length>0){
var tmp_gold_info = {}
ALL.gold_fingers.forEach(function(item2){
tmp_gold_info[item2.type] = item2.name
})
var layer_gold_type = /top/ig.test(item.signalL) ? "top" : "bot"
if(tmp_gold_info[layer_gold_type]){
var tmp_info = GEN.copperArea({layer1:tmp_gold_info[layer_gold_type],resolution_value:1})
// var tmp_info = GEN.exposedArea({layer1:item.signalL,mask1:tmp_gold_info[layer_gold_type]})
var tmp_data = {}
if(layer_gold_type == "top") {
tmp_data.sf_area_ref_layer_front = tmp_gold_info[layer_gold_type]
tmp_data.sf_area_gold_area_front = tmp_info.area
}
if(layer_gold_type == "bot"){
tmp_data.sf_area_ref_layer_back = tmp_gold_info[layer_gold_type]
tmp_data.sf_area_gold_area_back = tmp_info.area
}
save_job_info({
jobid: JobId,
jobinfohash: tmp_data
})
save_layerinfo({
jobid: JobId,
layer: item.signalL,
layerinfohash: {
sf_area_ref_layer: tmp_gold_info[layer_gold_type],
sf_area_gold_area: tmp_info.area
}
})
}
}
if(item.solderL){
var tmp_info = GEN.copperArea({layer1:item.solderL,resolution_value:1})
// 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;
// todo carbon 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_area
}
})
}
})
GEN.clearLayers()
GEN.affectedLayer({ affected: 'no', mode: 'all' })
console.log("==================================> Drill analysis")
// 钻孔
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:tmp_matrix[v]["drl_start"],end:tmp_matrix[v]["drl_end"]}
})
var drillRes = analysisDrill(drillToSignals,step) // 钻孔分析结果
console.log("===============drillRes:" + _.toString(drillRes));
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("==================================> chk signals analysis")
// 创建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]
})
// signal层分析结果
var res = analysisChkAttr({layers:signalLayers, info:info, step:step, job:job, oChecklistName:oChecklistName,jobpath:jobpath})
// 数据入库
Object.keys(res).forEach(function(key){
var val = res[key]
for(var key2 in val){
if(key2 == "min_ar_npth"){
if(Number(val[key2]) == 0 || Number(val[key2]) == 999){
delete val.min_ar_npth
}
}
}
save_layerinfo({
jobid: JobId,
layer: key,
layerinfohash: val
})
})
GEN.closeStep()
})
// 保存
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(par.export_path != "" && par.export_mode != "" && par.export_submode != "" ){
if(fs.exists(par.export_path)){
GEN.COM("export_job",{job:job,path:par.export_path,mode:par.export_mode,submode:par.export_submode,overwrite:"yes",format:"genesis",output_name:job})
GEN.COM("disp_on")
GEN.COM("origin_on")
} else {
resultData.push({ type: "error", title: "导出路径不存在!", detail: [{ desc: par.export_path }] });
}
}
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 UPLOAD_LAYER_MATRIX(props){
var job = props.job
props.jobcategory = props.jobcategory || "work"
var matrix = ANALYSIS_STACKUP({job:job, jobcategory:props.jobcategory});
Omatrix = matrix
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 == 'ftdrill'){
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 (/^ftdrill(\d+)-(\d+)/.test(layer.odb_name)){ // /^d(\d+)\-(\d+)$/
var tmp = /^ftdrill(\d+)-(\d+)/.exec(layer.odb_name)
var drl_star = tmp[1];
var drl_end = tmp[2];
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.name = 'laser' + drl_star + '-' + drl_end;
layer.type = 'laser_drill'; // 镭射
} else if( drl_star == 1 || drl_end == layer_count ){
layer.name = 'drill' + drl_star + '-' + drl_end;
layer.type = 'blind_drill'; // 埋孔
} else{
layer.name = 'drill' + drl_star + '-' + drl_end;
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})
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
// }
// }
if(Omatrix[layer] && Omatrix[layer].name){
// if(!(/^drill/ig.test(Omatrix[layer].tl_name))){
layer = Omatrix[layer].name
// }
}
var layerinfohash = props.layerinfohash;
Object.keys(layerinfohash).forEach(function(key){
var val = layerinfohash[key];
if(val && val != ""){
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, layer:layer},
data:{value:val},
})
});
}
}
})
}
function save_stack_info(props){
var info = props.info
var table = "pdm_job_stack_drills"
info.job_id = JobId
var drl_name = info.drl_name
db.query("",function(q){
return q.deleteRow({
table:table,
where:{job_id:JobId, drl_name: drl_name}
})
});
console.log(_.toString(info))
var Re = db.query("",function(q){
return q.insertRow({
table:table,
data:info,
return_field:'job_id',
})
});
}
function save_panel_info(props){
var info = props.info
var table = props.table
info.job_id = JobId
var job_id = info.job_id || JobId
var step_name = info.step_name
db.query("",function(q){
return q.deleteRow({
table:table,
where:{job_id:job_id, step_name: step_name}
})
});
db.query("",function(q){
return q.insertRow({
table:table,
data:info
})
});
}
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"}
var tmp = GEN.getProfileLimits({job:this.job,step:this.array_step,units:"mm"})
var size1 = Number(tmp.xsize)
var size2 = Number(tmp.ysize)
if(size1 > size2){
var tmpsize = size2
size2 = size1
size1 = tmpsize
}
if(props == "xsize"){
return size1.toFixed(2)
}
if(props == "ysize"){
return size2.toFixed(2)
}
}
T_m_p.prototype.analysis_vc_pcs_count_on_panel = function(props){ //
if(!this.array_step){return "_error"}
var has_step = has_steps({job:this.job, pcs_step:this.pcs_step ,array_step:this.array_step}) // 有无拼版关系
if(has_step){
// arr 中 pcs数量
var tmp = GEN.getRepeat({job:job, step:array_step})
return tmp.length
}
return "_todo"
}
T_m_p.prototype.analysis_pcs_count_on_array = function(props){ //
if(!this.array_step){return "_error"}
var has_step = has_steps({job:this.job, pcs_step:this.pcs_step ,array_step:this.array_step}) // 有无拼版关系
if(has_step){
// arr 中 pcs数量
var tmp = GEN.getRepeat({job:job, step:array_step})
return tmp.length
}
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].odb_name
var cover_layer = laser_layers[i+1].odb_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].odb_name + "_cover"
GEN.selClearFeature()
GEN.workLayer({name:layers[0].odb_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].odb_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].odb_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_exist2 = function(props){ // 存在某某层? string
var layers = Object.keys(this.matrixInfo.matrix)
if(/string/ig.test(typeof(props))){
return layers.indexOf(props) >= 0 ? "yes" : "no"
} else {
var res = "no"
props.forEach(function(v){
if(layers.indexOf(v)>=0){
res = "yes"
}
})
return res
}
}
T_m_p.prototype.analysis_layer_exist = function(props){ // 存在某某层? string
var layers = Object.keys(this.matrixInfo.matrix)
if(/string/ig.test(typeof(props))){
return layers.indexOf(props) >= 0 ? "yes" : "no"
} else {
var res = "no"
props.forEach(function(v){
if(layers.indexOf(v)>=0){
res = "yes"
}
})
return res
}
}
T_m_p.prototype.analysis_laser_via_on_buried_hole = function(){ // via孔在埋孔上
var t = this
// 找出 镭射孔 机械孔
var laser_layers = []
var buried_hole = []
for (var key in t.matrix) {
var val = t.matrix[key]
if(val.type == "laser_drill"){
laser_layers.push(key)
} else if(val.type == "blind_drill" || val.type == "bury_drill"){
buried_hole.push(key)
}
}
var res = "no"
if(buried_hole.length>0 && laser_layers.length){ // 有机械孔 和镭射
GEN.openStep({job:t.job,name:t.pcs_step})
GEN.affectedLayer({affected:'no',mode:'all'})
try {
laser_layers.forEach(function(laser){
GEN.workLayer({name:laser,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
buried_hole.forEach(function(buried){
GEN.selRefFeat({layers:buried,use:'filter',mode:'touch'})
if(GEN.getSelectCount()>0){
res = "yes"
throw "yes"
}
})
})
} catch (msg) { }
GEN.closeStep()
}
return res
}
T_m_p.prototype.analysis_milling_bit_size = function(){ // todo
return "_todo"
}
T_m_p.prototype.analysis_milling_length_card = function(){ // todo
var allStep = [this.pcs_step, this.array_step]
var res = 0
var that = this;
console.log("============analysis_milling_length_card=============");
console.log("========step========:"+_.toString(allStep));
var steps = GEN.getStepList({job:this.job})
allStep.forEach(function(step){
if(steps.indexOf(step)>=0){
GEN.openStep({job:that.job,name:step})
var tmp = "length_tmp"
if(GEN.isLayerExists({job:that.job,layer:tmp})){GEN.deleteLayer({job:that.job,layer:[tmp]})}
GEN.createLayer({job:that.job,layer:tmp,conext:'misc',type:'document'})
GEN.COM("profile_to_rout,layer="+tmp+",width=1")
var feautres = GEN.getFeatures({job:that.job,step:step,layer:tmp,units:"mm"})
fs.writeFile("/home/samba/tmp/tmp.js", _.toString(feautres))
// 根据feautres 算出周长
var milling = Object.keys(feautres).reduce(function(a,b){
var value = feautres[b]
if (value.type=="line"){
length = Math.sqrt((Number(value.xe)-Number(value.xs))*(Number(value.xe)-Number(value.xs)) + (Number(value.ye)-Number(value.ys))*(Number(value.ye)-Number(value.ys)))
a += length
} else if (value.type=="arc") {
a += arcLength(Number(value.xs),Number(value.ys),Number(value.xe),Number(value.ye),Number(value.xc),Number(value.yc))
}
return a
}, 0)
console.log("========milling:"+milling);
res += milling
console.log("========res:"+res);
GEN.deleteLayer({job:that.job,layer:[tmp]})
}
})
res = res/1000
return res.toFixed(3)
}
T_m_p.prototype.analysis_milling_length_array = function(){ // todo
if(!this.array_step){return "_error"}
GEN.openStep({job:this.job,name:this.array_step})
var tmp = "length_tmp"
GEN.COM("profile_to_rout,layer="+tmp+",width=1")
var feautres = GEN.getFeatures({job:this.job,step:this.array_step,layer:tmp,units:"mm"})
// 根据feautres 算出周长
var milling = Object.keys(feautres).reduce(function(a,b){
var value = feautres[b]
if (value.type=="line"){
length = Math.sqrt((value.xe-value.xs)*(value.xe-value.xs) + (value.ye-value.ys)*(value.ye-value.ys))
a += length
} else if (value.type=="arc") {
a += arcLength(Number(value.xs),Number(value.ys),Number(value.xe),Number(value.ye),Number(value.xc),Number(value.yc))
}
return a
}, 0)
GEN.closeStep()
milling = milling/1000
return milling.toFixed(3)
}
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){
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_gold_finger = function(){ //
if(!ALL.gold_fingers){return "no"}
return ALL.gold_fingers.length > 0 ? "yes" : "no"
}
T_m_p.prototype.analysis_glod_finger_area = function(){ //
if(ALL.gold_fingers.length > 0){
GEN.openStep({job:this.job, name:this.pcs_step})
var gold_finger_area = {}
var res = 0;
ALL.gold_fingers.forEach(function(item){
var tmp = GEN.copperArea({layer1:item.name}).percent
res += Number(tmp)
// var tmp = GEN.copperArea({layer1:item.name}).percent + "%"
// var key = item.type == "top" ? "sf_area_gold_area_front" : "sf_area_gold_area_back"
// gold_finger_area[key] = tmp
})
GEN.closeStep()
if(res){
return String(res.toFixed(4)) + "%"
}
}
return "_todo"
}
T_m_p.prototype.analysis_ATS_sm_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]) ? "FRONT1" : "BACK1"
} else {
res = "FRONT1;BACK1"
}
return res
}
T_m_p.prototype.analysis_vc_id_print_side = function(){ // 检查文字层所在面次
var solder_mask_layers = this.matrixInfo.matrixVal.filter(function(v){return v.layer_type == "silk_screen"})
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 = "NA"
if(solder_mask_info.length == 0){
res = "NA"
} else if (solder_mask_info.length == 1) {
res = /top/ig.test(solder_mask_info[0]) ? "FRONT" : "BACK"
} else {
res = "FRONT / BACK"
}
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,name: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_c2c"] = 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_sm_width = symbolInfo_solder["min_width"]}
if(symbolInfo_solder["min_length"]){res[layer.signalL].min_smd_sm_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 = Number(res[0]), num2 = Number(res[1])
if(num1 > num2){
var tmp = num2
num2 = num1
num1 = tmp
}
if(a.width == "N/A"){
a.width = num1
a.length = num2
return a
}
if(num2 < a.length){
a.width = num1
a.length = num2
}else if(num2 == a.length && a.width > num1){
a.width = num1
a.length = num2
}
}
return a
},{width:"N/A",length:"N/A"})
return {
min_width:symbols.width,
min_length:symbols.length
}
}
function smdPitch(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: "smdPitch",
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\\;SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf && 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:"smd_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})
// 获取最小smd间距
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 createChklistAndRun(par) {
var checkLayers = par.layers
var items = par.items
GEN.createChklist({ // 创建checklist
chklist: oChecklistName,
items: items
})
GEN.chklistShow({
chklist: oChecklistName
})
GEN.affectedLayer({
affected: "yes",
layer: checkLayers,
clear_before: "yes"
})
items.forEach(function(v){
GEN.chklistRun({
chklist: oChecklistName,
nact: v.nact,
area: 'profile'
})
})
}
function analysisChkAttr(par) {
var layers = par.layers;
var hash = {};
var info = par.info;
var job = par.job;
var oChecklistName = par.oChecklistName
layers.forEach(function (v) {
saveMeans({job:job,step:par.step,chklist:oChecklistName,nact:1,layer:v,jobpath:par.jobpath})
hash[v] = {}
Object.keys(info).forEach(function (key) {
var val = info[key]
hash[v][key] = val.reduce(function (a, type) {
var tmp = GEN.getCheckAttr({
job: job,
step: par.step,
checklist: oChecklistName,
nact: 1,
attr: v + "_min_" + type
})
if (a === "N/A" && /\d+/.test(tmp)) {
tmp = Number(tmp)
a = tmp.toFixed(2)
}
if (/\d+/.test(a) && /\d+/.test(tmp) && Number(tmp) < Number(a)) {
tmp = Number(tmp)
a = tmp.toFixed(2)
}
return a
}, "N/A")
if(hash[v][key]=="N/A"){
hash[v][key] = 999
}
})
})
return hash
}
function analysisDrill(par, step){
// {"layer":"d1-2","symbol":"r3.937","start":"top","end":"isl2"}
// {"layer":"d1-2","symbol":"r35.0394","start":"top","end":"bottom"}
var job = Job.toLowerCase()
GEN.affectedLayer({affected:'no',mode:'all'})
var res = par.map(function(drill){
GEN.workLayer({name:drill.layer,display_number:2,clear_before:'yes'})
GEN.selClearFeature()
GEN.selectByFilter({feat_types:'pad', include_syms:drill.symbol})
if(GEN.getSelectCount()>0){
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;
var res = {}
steplist.forEach(function(step){
GEN.openStep({job:job,name: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()
})
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})
// 留下pitch最小的bga 如果pitch都一样大 就跳过
var min_pitch = bgaPitch({job:job,step:step,layer:tmp_layer})
if(min_pitch){
res.min_bga_pitch = (min_pitch-0) + (symbols.size-0)
}
// 分析数据
GEN.clearLayers()
// 尺寸
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"})
GEN.selContourize()
GEN.COM("sel_cont2pad,match_tol=0,restriction=,min_size=5,max_size=100,suffix=+++")
GEN.COM("cur_atr_set,attribute=.smd")
GEN.COM("sel_change_atr,mode=add")
var ck = "tmp_chk"
if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck })}
var tmpItem = {
name: "opingsize", 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: "SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf){ tmpItem.erf = PAR.erf }
GEN.createChklist({ chklist: ck, items: [tmpItem] })
GEN.chklistShow({ chklist: ck })
GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' })
var min_smd = ["min_smd_pad"]
min_smd = min_smd.map(function(v){
return GEN.getCheckAttr({job:job,step:step,checklist:ck,attr:v,nact:1})
})
min_smd = min_smd.filter(function(v){return v!="N/A"})
if(min_smd.length == 0){
res.min_bga_openging_size = "todo" // todo
} else {
res.min_bga_openging_size = min_smd.sort(function(a,b){return a-b})[0]
}
GEN.deleteLayer({job:job,layer:[solderL_tmp,solderL_tmp+"+++"]})
}
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 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:"p2p"}]})
var tmp_layer = tmp_layer2 + "_tmp"
selCopyLayer({job:job,layer:tmp_layer})
GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'});
// 获取最小bga间距
var features = GEN.getFeatures({job:job,step:step,layer:tmp_layer})
if(features && features.length){
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:num.toFixed(4),symbol:v.symbol}
})
var bga_min_pitch = tmp.sort(function(a,b){return a-b})[0]
res.bga_min_pitch = bga_min_pitch.num
// pitch 中选最小的
GEN.selClearFeature()
GEN.COM("filter_set,filter_name=popup,update_popup=no,profile=in")
GEN.COM("filter_set,filter_name=popup,update_popup=yes,slot=line,slot_by=length,min_len=0,max_len="+(bga_min_pitch.num/1000)+0.0002)
GEN.COM("filter_area_strt")
GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=none,inside_area=no,intersect_area=no")
GEN.COM("filter_reset,filter_name=popup")
}
// 所有BGA中间距最小的PAD大小
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]
// 删除非最小的
GEN.selectByFilter({include_syms:min_pad_symbol.symbol})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
res.bga_min_pitch_pad_size = min_pad_symbol.size
res.bga_min_pitch = (res.bga_min_pitch || 20) - 0 + (min_pad_symbol.size-0)
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:'cover'})
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"})
GEN.selContourize()
GEN.COM("sel_cont2pad,match_tol=0,restriction=,min_size=5,max_size=100,suffix=+++")
GEN.COM("cur_atr_set,attribute=.smd")
GEN.COM("sel_change_atr,mode=add")
var ck = "tmp_chk"
if(GEN.isChklistExists({job:job,step:step,chklist:ck})){ GEN.COM("chklist_delete", { chklist: ck })}
var tmpItem = {
name: "opingsize", 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: "SMD",
pp_check_missing_pads_for_drills:"Yes"
}
}
if(PAR.erf){ tmpItem.erf = PAR.erf }
GEN.createChklist({ chklist: ck, items: [tmpItem] })
GEN.chklistShow({ chklist: ck })
GEN.chklistRun({ chklist: ck, nact: 1, area: 'profile' })
var min_smd = ["min_smd_pad"]
min_smd = min_smd.map(function(v){
return GEN.getCheckAttr({job:job,step:step,checklist:ck,attr:v,nact:1})
})
min_smd = min_smd.filter(function(v){return v!="N/A"})
if(min_smd.length == 0){
res.bga_min_pitch_openging_size = "todo" // todo
} else {
res.bga_min_pitch_openging_size = min_smd.sort(function(a,b){return a-b})[0]
}
GEN.deleteLayer({job:job,layer:[solder_layer_tmp,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:"p2p"}]})
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 res
if(features && features.length){
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)
})
res = tmp.sort(function(a,b){return a-b})[0]
}
if (res) {
// 过滤掉pitch不是最小的线
GEN.COM("filter_set,filter_name=popup,update_popup=no,profile=in")
GEN.COM("filter_set,filter_name=popup,update_popup=yes,slot=line,slot_by=length,min_len=0,max_len="+(res/1000)+0.0002)
GEN.COM("filter_area_strt")
GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=none,inside_area=no,intersect_area=no")
GEN.COM("filter_reset,filter_name=popup")
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
GEN.workLayer({name:layer,display_number:1,clear_before:'yes'});
GEN.selRefFeat({layers:tmp_layer,use:'filter',mode:'touch'})
GEN.selReverse()
if(GEN.getSelectCount()>0){GEN.selDelete()}
}
GEN.deleteLayer({job:job,layer:tmp_layer})
GEN.deleteLayer({job:job,layer:tmp_layer1})
GEN.deleteLayer({job:job,layer:tmp_layer2})
// 矩阵
return res || 20.1
}
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
}
}
function has_steps(props){
var job = props.job
var pcs_step = props.pcs_step
var array_step = props.array_step
var res = GEN.getSubSteps({job:job, step:array_step})
return res.indexOf(pcs_step) >= 0
}
function unSelect(){
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'plated'}],profile:'all',operation:"unselect"})
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'via'}],profile:'all',operation:"unselect"})
GEN.selectByFilter({attribute:[{attribute:'.drill',option:'non_plated'}],profile:'all',operation:"unselect"})
}
function mkPath(path,list) {
console.log("--path:" + path);
if(list.length){
var newPath = path + '/' + list.shift()
if(!fs.dirExists(newPath)){
fs.mkdir(newPath)
console.log("--mkdir:" + newPath);
}
return mkPath(newPath,list)
} else {return path}
}
function saveMeans(props){
var job = props.job
var step = props.step
var chklist = props.chklist
var nact = props.nact
var layer = props.layer
// 获取meas
var meas = GEN.getCheckMeas({job:job,step:step,chklist:chklist,nact:nact,layer:layer})
var basepath = props.jobpath+"/user/opcam/steps"
var respath = mkPath(basepath,[step,"chk",chklist+"_"+nact,layer])
fs.writeFile(respath+"/meas",meas.join("\n"))
fs.chmod(respath+"/meas",777)
}
// 算弧长
function arcLength(x1,y1,x2,y2,x3,y3){
var cos0 = +((x3-x1)*(x2-x3) + (y3-y1)*(y2-y3)) / (Math.pow((Math.pow(x2-x3,2) + Math.pow(y2-y3,2)),0.5) * Math.pow((Math.pow(x3-x1,2) + Math.pow(y3-y1,2)),0.5))
var tmp = Math.acos(cos0)
var sin0 = Math.sin(tmp)
var length = +Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2)) / sin0 * tmp
return length
}
\ No newline at end of file
......@@ -429,18 +429,18 @@
"tl_name": [
{"orig_name" : ["top_enig","top-enig","enig_top"], "tl_name" : "enig_top" },
{"orig_name" : ["bot_enig","bot-enig","enig_bot"], "tl_name" : "enig_bot" },
{"orig_name" : ["^spt$","^past_top$"], "tl_name" : "past_top" },
{"orig_name" : ["^spb$","^past_botm$"], "tl_name" : "past_botm" },
{"orig_name" : ["^sst$","^silk_top$"], "tl_name" : "silk_top" },
{"orig_name" : ["^ssb$","^silk_bot$"], "tl_name" : "silk_bot" },
{"orig_name" : ["^smt$","^sm_top$"], "tl_name" : "sm_top" },
{"orig_name" : ["^smb$","^sm_botm$"], "tl_name" : "sm_botm" },
{"orig_name" : ["top_paste","^spt$","^past_top$"], "tl_name" : "past_top" },
{"orig_name" : ["bottom_paste","^spb$","^past_botm$"], "tl_name" : "past_botm" },
{"orig_name" : ["top_silk","^sst$","^silk_top$"], "tl_name" : "silk_top" },
{"orig_name" : ["bottom_silk","^ssb$","^silk_bot$"], "tl_name" : "silk_bot" },
{"orig_name" : ["top_solder","^smt$","^sm_top$"], "tl_name" : "sm_top" },
{"orig_name" : ["bottom_solder","^smb$","^sm_botm$"], "tl_name" : "sm_botm" },
{"orig_name" : "^top$", "tl_name" : "top" },
{"orig_name" : "^drill$", "tl_name" : "drill" },
{"orig_name" : ["outline.art","^outline$"], "tl_name" : "outline" },
{"orig_name" : ["^board_outline$","outline.art","^outline$"], "tl_name" : "outline" },
{"orig_name" : ["^rout$","\\.rou$"], "tl_name" : "rout" },
{"orig_name" : "^bottom$", "tl_name" : "bottom" },
{"orig_name" : ["^isl(\\d+)$","^layer_(\\d+)$"], "tl_name" : "l_($1)"},
{"orig_name" : ["^l(\\d+)","^isl(\\d+)$","^layer_(\\d+)$"], "tl_name" : "l_($1)"},
{"orig_name" : ["_isl(\\d+)_isl(\\d+)","d(\\d+)-(\\d+)"], "tl_name" : "d_($1)-($2)"},
{"orig_name" : ["_top_isl(\\d+)"], "tl_name" : "d_1-($1)"},
{"orig_name" : ["_isl(\\d+)_bottom"], "tl_name" : "d_($1)-($1+1)"}
......@@ -572,13 +572,13 @@
{"orig_name" : ["mask_top\\.art","psm\\.art","sm_top"], "tl_name" : "sm_top" },
{"orig_name" : ["mask_bot\\.art","ssm\\.art","sm_bot"], "tl_name" : "sm_botm" },
{"orig_name" : ["^top$","^top.art$"], "tl_name" : "top" },
{"orig_name" : ["l(\\d)\\.art$","^0(\\d+).*ccp_ms","^s(\\d+)\\.art","lay(\\d+)\\.art","layer_(\\d+)"], "tl_name" : "l_($1)"},
{"orig_name" : ["^0?(\\d+)_.*\\.art$","^l(\\d+)\\.art$","^0(\\d+).*ccp_ms","^s(\\d+)\\.art","lay(\\d+)\\.art","layer_(\\d+)"], "tl_name" : "l_($1)"},
{"orig_name" : ["^bottom$","^bottom\\.art$"], "tl_name" : "bottom" },
{"orig_name" : ["-(\\d+)-(\\d+)\\.drl$","(\\d+)-(\\d+)-laser\\.drl$","d(\\d+)-(\\d+)"], "tl_name" : "d_($1)-($2)"},
{"orig_name" : ["\\.rou$","^rout$"], "tl_name" : "rout" },
{"orig_name" : "fab.art", "tl_name" : "fab.art" },
{"orig_name" : ["multipack.art","^array$"], "tl_name" : "array" },
{"orig_name" : ["^outline"], "tl_name" : "outline" },
{"orig_name" : ["outline"], "tl_name" : "outline" },
{"orig_name" : ["^pst\\.art$","top-enig","enig_top"], "tl_name" : "enig_top" },
{"orig_name" : ["^sst\\.art$","bot-enig","enig_bot"], "tl_name" : "enig_bot" },
],
......@@ -810,6 +810,7 @@
"format": "Excellon2_4",
"format_params": function(props){
var params = props.params
if (params.ncdrill && !params.nc_param){params.nc_param = params.ncdrill}
if(params.nc_param){
var leading = params.nc_param["SUPPRESS_LEAD_ZEROES"]
var trailing = params.nc_param["SUPPRESS_TRAIL_ZEROES"]
......@@ -847,12 +848,12 @@
"tl_name": [
{"orig_name" : ["^pmt\\.art$","\\.pma$","SoldPasteTop\\.ger","past_top"], "tl_name" : "past_top" },
{"orig_name" : ["^pmb\\.art$","\\.pmb$","SoldPasteBot\\.ger","past_botm"], "tl_name" : "past_botm" },
{"orig_name" : ["^sst\\.art$","\\.ssa$","SilkScrnTop\\.ger","silk_top"], "tl_name" : "silk_top" },
{"orig_name" : ["^ssb\\.art$","\\.ssb$","SilkScrnBot\\.ger","silk_bot"], "tl_name" : "silk_bot" },
{"orig_name" : ["^smt\\.art$","\\.sma$","SoldMask1Top\\.ger","sm_top"], "tl_name" : "sm_top" },
{"orig_name" : ["^smb\\.art$","\\.smb$","SoldMask1Bot\\.ger","sm_bot"], "tl_name" : "sm_botm" },
{"orig_name" : ["tsilk","^sst\\.art$","\\.ssa$","SilkScrnTop\\.ger","silk_top"], "tl_name" : "silk_top" },
{"orig_name" : ["bsilk","^ssb\\.art$","\\.ssb$","SilkScrnBot\\.ger","silk_bot"], "tl_name" : "silk_bot" },
{"orig_name" : ["tmask","^smt\\.art$","\\.sma$","SoldMask1Top\\.ger","sm_top"], "tl_name" : "sm_top" },
{"orig_name" : ["bmask","^smb\\.art$","\\.smb$","SoldMask1Bot\\.ger","sm_bot"], "tl_name" : "sm_botm" },
{"orig_name" : ["^top$","^top.art$"], "tl_name" : "top" },
{"orig_name" : ["^v(\\d+)\\.art$","^g(\\d+)\\.art$","^s(\\d+)\\.art$","\\.l(\\d+)$","Copper(\\d+)\\.ger$","^layer_(\\d+)"], "tl_name" : "l_($1)"},
{"orig_name" : ["^l(\\d+).*\\.art$","^v(\\d+)\\.art$","^g(\\d+)\\.art$","^s(\\d+)\\.art$","\\.l(\\d+)$","Copper(\\d+)\\.ger$","^layer_(\\d+)"], "tl_name" : "l_($1)"},
{"orig_name" : ["^bot\\.art$","^bottom$","^bottom.art$"], "tl_name" : "bottom" },
{"orig_name" : ["\\.d(\\d+)$"], "tl_name" : "d_($1)-($1+1)"},
{"orig_name" : ["thruHolePlated_(\\d+)_(\\d+)\\.ncd","(\\d+)-(\\d+)\\.drl$","^drill(\\d+)-(\\d+)$","^d_(\\d+)-(\\d+)$"], "tl_name" : "d_($1)-($2)"},
......@@ -860,18 +861,10 @@
{"orig_name" : ["\\.rou$","^rout$"], "tl_name" : "rout" },
{"orig_name" : "fab.art", "tl_name" : "fab.art" },
{"orig_name" : ["multipack.art","^array$"], "tl_name" : "array" },
{"orig_name" : ["\\.bol$","PnlContourNonPlated\\.ger","^outline"], "tl_name" : "outline" },
{"orig_name" : ["outline\\.art$","\\.bol$","PnlContourNonPlated\\.ger","^outline"], "tl_name" : "outline" },
{"orig_name" : ["top-enig","enig_top"], "tl_name" : "enig_top" },
{"orig_name" : ["bot-enig","enig_bot"], "tl_name" : "enig_bot" },
],
"mergerule" : {
drill: ["(\\d+)-(\\d+)\\.drl$"],
profile:["^drill.\\art$"],
laser : {
tl_name: "drill($1)-($2)",
regs: ["(\\d+)-(\\d+)\\.drl$"]
}
}
]
},
"Vivo":{
"step": "cad",
......
......@@ -10,6 +10,8 @@ var Job = $.job;
var JobId = $.job_id;
try {
GEN.renameStep({job:'demo',name:'pcb_1',new_name:'pcb_a'})
return "Done"
} catch (e) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment