=head NAME: DESCRIPTION: Run Map PARAMETER: [ { name : 'step', title : 'Panel Step', type : 'LineEdit', value : 'E:/', pack : {row:0,column:1}, property : { tool_tip:'panel step名称,如未设置,默认为panel' } }, { name : 'units', title : 'Units', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'mm',text:'mm'}, {name:'inch',text:'inch'}, ], tool_tip:'脚本运行genesis的工作单位,如未设置,默认为inch' }, pack : {row:1,column:1}, }, { name : 'panel_category', title : '板框类型', type : 'TextEdit', property:{tool_tip:'未定义则默认为标准的category:overlay'}, setter:function(obj,value,self){ obj.setPlainText(value); }, getter:function(obj,self){ return obj.plainText } }, { name : 'version', title : 'Version', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'release',text:'正式版'}, {name:'test',text:'测试版'}, {name:'select',text:'选择版本'}, ], tool_tip:'板框版本:正式版为1,测试版为0,如未设置,默认为选择版本' }, pack : {row:1,column:1}, }, { name : 'change_standard_symbol', title : '转为自定义Symbol', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'Yes',text:'Yes'}, {name:'No',text:'No'}, ], tool_tip:'因标准symbol在旋转后会失去角度信息,所以需转为自定义symbol,默认为yes' }, pack : {row:1,column:1}, }, { name : 'condition', title : '全部添加', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'Yes',text:'Yes'}, {name:'No',text:'No'}, ], tool_tip:'全部添加如果是YES 所有SYMBOL添加出来(仅调试使用,将忽略symbol的添加条件的判断),默认为No' }, pack : {row:1,column:1}, }, { name : 'debug_priority', title : '调试等级', type : 'SpinBox', pack : {row:1,column:1}, property : { tool_tip:'symbol的优先级小于设定调试等级的,将不会添加出来,默认为0' } }, { name : 'debug_add_size_symbol', title : '调试-添加大小Symbol', type : 'ComboBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'Yes',text:'Yes'}, {name:'No',text:'No'}, ], tool_tip:'设定为yes,将按图形symbol->孔symbol->map symbol的优先级顺序添加,否则直接添加map symbol,默认为No' }, pack : {row:1,column:1}, }, { name : 'save_job', title : '保存料号', type : 'RadioBox', property : { size_policy:'Expanding,Fixed', item_list:[ {name:'Yes',text:'Yes'}, {name:'No',text:'No'}, ], tool_tip:'脚本结束后自动保存料号,未设定,默认为No' }, pack : {row:1,column:1}, } ] VERSION_HISTORY: V1.00 2019-05-17 Alan Fu 1.新版本. HELP: <html><body bgcolor="#DDECFE"> <font size="3" color="#003DB2"><p>功能简介</p></font> <p> Overlay Run map </p> </body></html> =cut ################################################################################################################# ################################################################################################################# use strict; use utf8; use JSON; use Encode; use Data::Dump 'dump'; use Number::Format 'round'; use_module('TL_GenMath'); # my $Json = new JSON; my $Math = TL::GenMath->new(); my ($Job,$Step,$Return) = ($JOB,undef,'finish'); my (@Report,$M,$S,$P,$L,$D); my ($SIZE_DATA,$MAP_DATA);#SYMBOL、计算模块、计算模型 my $CALC_COUNT; my (%SymbolExists,@MapOkPads,@MapFailPads,$isSymbolExitsFilter); # $PAR->{step} = 'panel' if(!defined($PAR->{step})); $PAR->{units} = 'inch' if(!defined($PAR->{units})); $PAR->{panel_category} = eval($PAR->{panel_category}) if $PAR->{panel_category}; $PAR->{version} = 'select' if(!defined($PAR->{version})); $PAR->{change_standard_symbol} = 'Yes' if(!defined($PAR->{change_standard_symbol})); $PAR->{condition} = 'No' if(!defined($PAR->{condition})); $PAR->{debug_priority} = 0 if(!defined($PAR->{debug_priority})); $PAR->{debug_add_size_symbol} = "No" if(!defined($PAR->{debug_add_size_symbol})); $PAR->{save_job} = 'No' unless $PAR->{save_job}; $PAR->{safe_dist} = 0.05 if(!defined($PAR->{safe_dist})); $PAR->{map_layer} = 'pnl-map' unless $PAR->{map_layer}; $PAR->{map_layer_error} = 'pnl-map-error' unless $PAR->{map_layer_error}; # my $JOB_PATH = $GEN->getJobPath(job=>$Job); ################################################################################################################# ################################################################################################################# try { show_loading("判断是否选择料号...",0,position=>'n'); unless($Job){ $GUI->msgbox(-icon=>'error',-text=>"请先选择料号后再执行脚本!"); return 'Cancel'; } ## update_loading("检查${Job}是否存在...",0,position=>'n'); unless ( $GEN->isJobExists(job=>$Job) ){ $GUI->msgbox(-icon=>'error',-text=>"料号${Job}不存在,请确认!"); return 'Cancel'; } ## update_loading("正在打开料号${Job}...",0,position=>'n'); $GEN->openJob(job=>$Job) unless ($GEN->isJobOpen(job=>$Job)); ## update_loading("过滤工作STEP...",0,position=>'n'); my $ans_step = get_work_step(); return $ans_step if $ans_step; ## my $panel_category = $PAR->{panel_category} || 'overlay'; unless(defined($panel_category)){ $GUI->msgbox(-icon=>'error',-text=>"未定义板框运行类型!"); return "error"; } ## update_loading("获取并选择板框执行版本..",0,position=>'n'); my $version; my $version_list = $IKM->select_arrayhash(-table=>"pdm_panelmap",-field=>"version",-order=>"version ASC",-where => {category=>$panel_category}); my @tmp_version; foreach my $ver(sort{$a->{version} <=> $b->{version} } @$version_list){ push @tmp_version,$ver->{version} unless grep {$_ eq $ver->{version}} @tmp_version; } $version_list = \@tmp_version; if( scalar(@$version_list) == 1 ){ $version = $version_list->[0]; } elsif($PAR->{version} eq "release" and grep( {$_ eq '1'} @$version_list) ){ $version = "1"; } elsif($PAR->{version} eq "test" and grep( {$_ eq '0'} @$version_list) ){ $version = "0"; } else{ my @version = $GUI->select_from_treeview( -headstock=>'tl-question', -defaultsize=>[200,300], -selectmode=>'single', -title=>__('Please Select Version'), -treemapping=>[version=>'Glib::String'], -treecolumns=>[ {title=>__('Version'),renders=>[{class=>'Text',text=>'version'}]}, ], -treedata=>[map {{version=>$_}} @$version_list], -valuefield=>'version', -selectvalue=>$version_list->[0], -searchfield=>['version'], ); return 'Cancel' unless(@version); $version = $version[0]; } ## update_loading("打开${Step}STEP...",0,position=>'n'); $GEN->openStep(job=>$Job,name=>$Step); $GEN->clearLayers(); $GEN->affectedLayer( mode=>'all',affected=>'no' ); $GEN->COM( "sel_options,clear_mode=clear_after,display_mode=all_layers,area_inout=inside,area_select=select,select_mode=standard,area_touching_mode=exclude"); $GEN->zoomHome(); $GEN->units(type=>$PAR->{units}); ## update_loading("解析板框代码并确认配置信息,请稍候..",0,position=>'n'); my $tmp_db_map_data = $IKM->select_arrayhash( -table=>"pdm_panelmap", -field=>["id", "parent_id", "version", "category", "flow_order", "symbol_name", "row_name", "map_symbol" , "hole_symbol" , "pattern_symbol", "condition", "content", "status", "active", "map_class", "avoid_hole_class" , "avoid_pattern_class" , "row_type" , "layer_type", "priority"], -order=>"version ASC,parent_id ASC,flow_order ASC", -where => {version=>$version,active=>1,category=>$panel_category,row_type=>['Category','Public','Map Header','Map Symbol','Map Footer']}, ); foreach my $item (@$tmp_db_map_data){ $item->{avoid_hole_class} = eval($item->{avoid_hole_class}); $item->{avoid_pattern_class} = eval($item->{avoid_pattern_class}); $item->{map_class} = eval($item->{map_class}); my %map_class; if ($item->{map_class}){ foreach my $cls (@{$item->{map_class}}){ $map_class{$cls} = 1; } } $item->{map_class} = \%map_class; } my @map_rows; my @map_footer_rows; my $row_num = 0; my $sub_execute_db_map_data; $sub_execute_db_map_data = sub{ my $db_data = shift; foreach my $row (@$db_data){ $row->{_row_num} = ++$row_num; if ($row->{row_type} eq 'Public'){ $row->{priority} = 9999; } elsif($row->{row_type} eq 'Map Header'){ $row->{priority} = 8888; } elsif($row->{row_type} eq 'Map Footer'){ $row->{priority} = -8888; } if ($row->{row_type} eq 'Map Footer'){ push @map_footer_rows,$row; } elsif ($row->{row_type} ne 'Category'){ push @map_rows,$row; } $sub_execute_db_map_data->([grep{$_->{parent_id} eq $row->{id}} @$tmp_db_map_data]); } }; $sub_execute_db_map_data->([grep{!($_->{parent_id})} @$tmp_db_map_data]); my $row_count = scalar(@map_rows) + 2; my $row_n = 0; foreach my $row (sort{$b->{priority} <=> $a->{priority} || $a->{_row_num} <=> $b->{_row_num}} @map_rows){ #条件 next if ($PAR->{debug_priority} and $row->{priority} < $PAR->{debug_priority}); my $disp_name = $row->{row_name}; $disp_name =~ s/\n/ /g; update_loading('正在计算['.$disp_name.']...',($row_n++)/$row_count); my $condition = eval($row->{condition}); if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]条件失败! \n $@"); return "Error"; } $condition = $condition->(%$row) if($condition and ref($condition) eq "CODE"); next unless((!defined($condition) or $condition == 1) or $PAR->{condition} eq "Yes"); #计算 my $calculate_pads; $calculate_pads = eval($row->{content}); if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]坐标失败! \n $@"); return "Error"; } if (ref($calculate_pads) eq 'CODE'){ eval{ $calculate_pads = $calculate_pads->(%$row); }; if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]坐标失败! \n $@"); return "error"; } } PUSH_MAP_DATA($calculate_pads,$row); } $GEN->openStep(job=>$Job,name=>$Step); $GEN->units(type=>$PAR->{units}); $PAR->{map_layer} = 'pnl-map' unless $PAR->{map_layer}; $PAR->{map_layer_error} = 'pnl-map-error' unless $PAR->{map_layer_error}; $GEN->deleteLayer(job=>$Job,layer=>[$PAR->{map_layer_error}]); $GEN->createLayer(job=>$Job,layer=>$PAR->{map_layer},context=>'misc',type=>'signal') unless ($GEN->isLayerExists(job=>$Job,layer=>$PAR->{map_layer}));; $GEN->clearLayers(); $GEN->affectedLayer(mode=>'all',affected=>'no'); $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>[$PAR->{map_layer}],clear_before=>'yes'); $GEN->COM('sel_all_feat'); $GEN->selDelete() if $GEN->getSelectCount(); show_loading('正在pnl-map层添加Symbol...',0,position=>'n'); my $pad_count = scalar(@MapOkPads) + scalar(@MapFailPads) + 2; my $pad_n = 1; foreach my $pad (@MapOkPads){ update_loading('正在'.$PAR->{map_layer}.'层添加Symbol['.$pad->{symbol}.']'." $pad_n/$pad_count",$pad_n/$pad_count); $GEN->addPad(%$pad); $pad_n++; } $GEN->workLayer(name=>$PAR->{map_layer},display_number=>1,clear_before=>'yes'); if (@MapFailPads){ $GEN->createLayer(job=>$Job,layer=>$PAR->{map_layer_error},context=>'misc',type=>'signal') unless ($GEN->isLayerExists(job=>$Job,layer=>$PAR->{map_layer_error}));; $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>[$PAR->{map_layer_error}],clear_before=>'yes'); $GEN->COM('sel_all_feat'); $GEN->selDelete() if $GEN->getSelectCount(); foreach my $pad (@MapFailPads){ update_loading('正在'.$PAR->{map_layer_error}.'层添加Symbol['.$pad->{symbol}.']'." $pad_n/$pad_count",$pad_n/$pad_count); $GEN->addPad(%$pad); $pad_n++; } $GEN->workLayer(name=>$PAR->{map_layer_error},display_number=>1,clear_before=>'yes'); $GEN->displayLayer(name=>$PAR->{map_layer},number=>2); } update_loading("pnL-map层创建完成,脚本即将结束..",0,position=>'n'); foreach my $row (sort{$b->{priority} <=> $a->{priority} || $a->{_row_num} <=> $b->{_row_num}} @map_footer_rows){ my $disp_name = $row->{row_name}; $disp_name =~ s/\n/ /g; my $condition = eval($row->{condition}); if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]条件失败! \n $@"); return "Error"; } $condition = $condition->(%$row) if($condition and ref($condition) eq "CODE"); next unless((!defined($condition) or $condition == 1) or $PAR->{condition} eq "Yes"); #计算 my $calculate_pads; $calculate_pads = eval($row->{content}); if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]坐标失败! \n $@"); return "Error"; } if (ref($calculate_pads) eq 'CODE'){ eval{ $calculate_pads->(%$row); }; if ($@) { $GUI->msgbox(-icon=>'error',-text=>"载入[$disp_name]坐标失败! \n $@"); return "error"; } } } ## unless( @MapFailPads or $PAR->{map_error} ){ $GEN->deleteLayer(job=>$Job,step=>$Step,layer=>$PAR->{map_layer_error}); } hide_loading(); $GUI->msgbox(-text=>"请确认 $PAR->{map_layer} 层中的Symbol位置,并手动在 $PAR->{map_layer_error} 修正好!") if ( @MapFailPads or $PAR->{map_error} ); my $info_file = $JOB_PATH.'/user/PNL_map_info'; open(my $fh,'>',$info_file); print $fh dump({P=>$P,L=>$L,D=>$D,S=>$S}); close($fh); ##报告 if (@Report){ #push @Report,"\n\n".$GEN->getUserName().":".$DB->get_now(); my $Report = join("\n",@Report); $Report =~ s/\n/<br>/g; $Report =~ s/\s/\<p\>\&NBSP\;\<\/p\>/g; my $report_save = '<html><body text="#000022">'; $report_save .= "$Report"; $report_save .= '</body></html>'; $IKM->update_flow_report(-report=>$report_save); } else{ $IKM->update_flow_report(-report=>''); } ##保存料号 if( $PAR->{save_job} =~ /yes/i ){ show_loading("$Job 正在保存料号,请稍候...",0,position=>'n'); $GEN->checkInout(job=>$Job,mode=>'out'); $GEN->saveJob(job=>$Job); hide_loading(); } ###output and return status, if genesis error, it will output genesis error command unless ($GEN->{STATUS}){ return $Return; } else{ $GUI->msgbox(-icon=>'error',-text=>join("\n",@{$GEN->{STATUS}})); #addFlowNotes(-notes=>" Genesis Error:\n ".join("\n ",@{$GEN->{STATUS}})); return 'Error'; } } catch Error::Simple with { my $error = shift; $GUI->msgbox(-icon=>'error',-text=>$error); return 'Error'; } finally{ #$GEN->workLayer(name=>,number=>1,clear_before=>'yes'); }; ################################################################################################################# ################################################################################################################# sub get_work_step { my @steps = $GEN->getStepList(job=>$Job); if ( @steps == 0 ) { $GUI->msgbox(-icon=>'error',-text=>'在料号中没有Step存在,你将退出!'); return 'Cancel'; } elsif (@steps != 0){ my @tmp_steps = grep(/^$PAR->{step}$/,@steps); if ( @tmp_steps == 0 ) { $GUI->msgbox(-icon=>'warning',-text=>'根据脚本参数过滤出来的step不存在,请检查资料或者脚本参数配置!'); return 'Cancel'; } elsif (@tmp_steps == 1) { $Step = $tmp_steps[0]; } else { update_loading("选择工作step...",0,position=>'n'); $Step = $GUI->select_step( -title=>'请选择工作 Step', -steplist=>[@tmp_steps], -default=>[$tmp_steps[0]], -gen=>$GEN, -selectmode=>'single' ); return 'Cancel' unless ($Step); } } return undef; } sub PUSH_MAP_DATA{ my ($calculate_pads,$item) = @_; return unless ref($calculate_pads) eq 'ARRAY'; #return unless defined $item->{name}; my @size_pads; foreach my $pad (@$calculate_pads){ $pad->{name} = $item->{symbol_name} unless $pad->{name}; $pad->{class} = $item->{map_class} unless $pad->{class}; if ($pad->{class} and $pad->{class}{'Pattern'}){ $pad->{pattern_symbol} = $item->{pattern_symbol} || $pad->{hole_symbol} || $item->{hole_symbol} unless $pad->{pattern_symbol}; } else{ delete $pad->{pattern_symbol}; } if ($pad->{class} and $pad->{class}{'Hole'}){ $pad->{hole_symbol} = $item->{hole_symbol} || $pad->{pattern_symbol} || $item->{pattern_symbol} unless $pad->{hole_symbol}; } else{ delete $pad->{hole_symbol}; } $pad->{map_symbol} = $item->{map_symbol} || $pad->{pattern_symbol} || $pad->{hole_symbol} unless $pad->{map_symbol}; unless (defined $pad->{cannot_move}){ if ($item->{priority} >= 99){ $pad->{cannot_move} = 1; } } $pad->{stack} = '1-'.$P->{layer_count} unless $pad->{stack}; unless($pad->{map_symbol}){ print dump($pad),"\n"; } if( (! $SymbolExists{$pad->{map_symbol}}) and $pad->{map_symbol} ne 'NO' and ($pad->{map_symbol} !~ /^(rect|oval|r|s|rc_ths)\d+/) and (! _isSymbolExists($pad->{map_symbol}))) { $pad->{map_symbol} = $pad->{pattern_symbol} || $pad->{hole_symbol}; } if ($PAR->{change_standard_symbol} eq 'Yes'){ if ($pad->{map_symbol} =~ /^(rect|oval|r|s)\d+/){ my $pnl_sym = 'pnl_' . $pad->{map_symbol}; unless ($SymbolExists{$pnl_sym} or _isSymbolExists($pnl_sym)){ _create_symbol($pnl_sym,$pad->{map_symbol}); } $pad->{map_symbol} = $pnl_sym; } } $SymbolExists{$pad->{map_symbol}} = 1; my @pad_tag = ('S'.($pad->{stack}) , $pad->{name}); if ($pad->{tag}){ if (ref($pad->{tag}) eq 'ARRAY'){ foreach my $k (@{$pad->{tag}}){ push @pad_tag,$k; } } elsif(ref($pad->{tag}) eq 'HASH'){ foreach my $k (sort keys %{$pad->{tag}}){ my $v = $pad->{tag}{$k}; if (defined $v){ push @pad_tag,$k.'='.$v; } else{ push @pad_tag,$k; } } } else{ push @pad_tag,$pad->{tag}; } } if ($pad->{size_shiftx}){ push @pad_tag , 'sx='.$pad->{size_shiftx}; } if ($pad->{size_shifty}){ push @pad_tag , 'sy='.$pad->{size_shifty}; } push @pad_tag , 'hs=' . $pad->{hole_symbol} if $pad->{hole_symbol}; push @pad_tag , 'ps=' . $pad->{pattern_symbol} if $pad->{pattern_symbol}; my $pad_attr = [{attribute=>'tl_string',text=>join(':',@pad_tag)}]; #push @$pad_attr,$PAR->{can_not_move_attr} if $pad->{cannot_move}; my $map_symbol = $pad->{map_symbol}; if ($PAR->{debug_add_size_symbol} eq 'Yes'){ $map_symbol = $pad->{pattern_symbol} || $pad->{hole_symbol} || $pad->{map_symbol}; } my $map_pad = { attributes=>$pad_attr, x => $pad->{x}, y => $pad->{y}, angle=> $pad->{angle} || 0, symbol=> $map_symbol , mirror => $pad->{mirror} }; my $size_pad = { x => $pad->{x}, y => $pad->{y}, stack => $pad->{stack}, hole_symbol => $pad->{hole_symbol}, pattern_symbol => $pad->{pattern_symbol} , angle => $pad->{angle}, class => $pad->{class}, name => $pad->{name}, }; push @{$MAP_DATA->{$pad->{name}}{$pad->{stack}}} , $pad; $size_pad = _shift_size_pad(pad=>$size_pad,shiftx=>$pad->{size_shiftx},shifty=>$pad->{size_shifty}); $size_pad->{angle} = $pad->{angle}; if ($pad->{failed}){ push @MapFailPads,$map_pad unless $map_pad->{symbol} eq 'NO'; } else{ push @MapOkPads,$map_pad unless $map_pad->{symbol} eq 'NO'; push @{$SIZE_DATA->{$pad->{name}}},$size_pad; } } } =h 如果以前检查过了那就不检查第二次 =cut sub _isSymbolExists{ my $symbol = shift; if(!defined($isSymbolExitsFilter->{$symbol})){ $isSymbolExitsFilter->{$symbol} = 0; if($GEN->isSymbolExists(job=>'genesislib',symbol=>$symbol) or $GEN->isSymbolExists(job=>$Job,symbol=>$symbol)){ $isSymbolExitsFilter->{$symbol} = 1; } } return $isSymbolExitsFilter->{$symbol}; } sub GET_AVOID_FEATS { my %par = @_; #(stack=>'1-8',class=>['S*:*','S-:grp'],name=>[],size_type =>'pattern'|'hole',range=>{x1=>,x2=>,y1=>,y2=>}) $par{size_type} = 'pattern' unless $par{size_type}; if (ref($par{class}) eq 'HASH'){ my @class; foreach my $k (sort keys %{$par{class}}){ push @class,$k; } $par{class} = \@class; } my @avoid_feats; if ($par{class}){ foreach my $name (keys %$SIZE_DATA){ foreach my $class (@{$par{class}}){ my ($stk_flag,@cls) = split(':',$class); my $ivt = 0; my $all = 0; if ($cls[0] =~ /^\!/){ $ivt = 1; $cls[0] =~ s/^\!//; } $all = 1 if (! $cls[0] or $cls[0] eq '*'); my $stks = _parse_stack_flag($par{stack},$stk_flag) if $stk_flag; foreach my $pad (@{$SIZE_DATA->{$name}}){ next unless $pad->{$par{size_type}.'_symbol'}; if (!$stks or ($stks and $stks->{$pad->{stack}})){ if ($all){ push @avoid_feats,{ x => $pad->{x}, y => $pad->{y}, symbol => $pad->{$par{size_type}.'_symbol'}, angle => $pad->{angle}, name => $name, stack => $pad->{stack}, } if $pad->{$par{size_type}.'_symbol'}; } else{ if ($ivt){ my $ok = 1; foreach my $_cls (@cls){ if ($pad->{class}{$_cls}){ $ok = 0; last; } } push @avoid_feats,{ x => $pad->{x}, y => $pad->{y}, symbol => $pad->{$par{size_type}.'_symbol'}, angle => $pad->{angle}, name => $name, stack => $pad->{stack}, } if ($ok and $pad->{$par{size_type}.'_symbol'}); } else{ my $ok = 0; foreach my $_cls (@cls){ if ($pad->{class}{$_cls}){ $ok = 1; last; } } push @avoid_feats,{ x => $pad->{x}, y => $pad->{y}, symbol => $pad->{$par{size_type}.'_symbol'}, angle => $pad->{angle}, name => $name, stack => $pad->{stack}, } if ($ok and $pad->{$par{size_type}.'_symbol'}); } } } } } } } if ($par{name}){ foreach my $name (keys %$SIZE_DATA){ foreach my $nam (@{$par{name}}){ my ($stk_flag,$nm) = split(':',$nam); next unless $nm eq $name; if ($stk_flag){ my $stks = _parse_stack_flag($par{stack},$stk_flag); foreach my $pad (@{$SIZE_DATA->{$name}}){ if ($stks->{$pad->{stack}}){ push @avoid_feats,{ x => $pad->{x}, y => $pad->{y}, symbol => $pad->{$par{size_type}.'_symbol'}, angle => $pad->{angle}, name => $name, stack => $pad->{stack}, } if ($pad->{$par{size_type}.'_symbol'}); } } } else{ foreach my $pad (@{$SIZE_DATA->{$name}}){ push @avoid_feats,{ x => $pad->{x}, y => $pad->{y}, symbol => $pad->{$par{size_type}.'_symbol'}, angle => $pad->{angle}, name => $name, stack => $pad->{stack}, } if ($pad->{$par{size_type}.'_symbol'}); } } } } } if ($par{exclude_name}){ my @tmp; my %flg; foreach my $nam (@{$par{exclude_name}}) { my ($stk_flag,$nm) = split(':',$nam); unless($stk_flag){ $stk_flag = 'S*'; $nm = $nam; } if ($stk_flag){ my $stks = _parse_stack_flag($par{stack},$stk_flag); foreach my $s (keys %$stks){ $flg{$s.':'.$nm} = 1; } } } foreach my $p (@avoid_feats) { my $k = $p->{stack}.':'.$p->{name}; push @tmp , $p unless $flg{$k}; } @avoid_feats = @tmp; } if ($par{range}){ $par{range} = [$par{range}] unless ref($par{range}) eq 'ARRAY'; my @tmp; foreach my $area (@{$par{range}}){ my $xmin = (exists $area->{x1}) ? $area->{x1} : $area->{xmin}; my $xmax = (exists $area->{x2}) ? $area->{x2} : $area->{xmax}; my $ymin = (exists $area->{y1}) ? $area->{y1} : $area->{ymin}; my $ymax = (exists $area->{y2}) ? $area->{y2} : $area->{ymax}; ($xmin,$xmax) = sort{$a <=> $b} sort ($xmin,$xmax); ($ymin,$ymax) = sort{$a <=> $b} sort ($ymin,$ymax); foreach my $feat (@avoid_feats) { my ($l,$s) = $feat->{symbol} =~ /(\d+\.?\d*)/g; my $sum = ($l + $s)/1000; if (TL::GenMath->is_range_intersect({min=>$xmin,max=>$xmax},{min=>$feat->{x} - $sum,max=>$feat->{x} + $sum}) or TL::GenMath->is_range_intersect({min=>$ymin,max=>$ymax},{min=>$feat->{y} - $sum,max=>$feat->{y} + $sum})) { push @tmp,$feat; } } } return \@tmp; } else{ return \@avoid_feats; } } sub _parse_stack_flag{ my ($stk,$stk_flag) = @_; my %stks; my $invert; $stk_flag = 'S*' unless $stk_flag; if ($stk =~ /^\!/){ $stk_flag =~ s/^\!//; $invert = 1; } if ($stk_flag eq 'S'){ $stks{$stk} = 1; } elsif($stk_flag eq 'SO' or $stk_flag eq 'SE'){ $stks{1 . '-' . $P->{layer_count}} = 1; } elsif($stk_flag eq 'S-'){ foreach my $s (@{$S->{$stk}{all_sub_stacks}}){ $stks{$s} = 1; } } elsif($stk_flag eq 'S+'){ foreach my $s (@{$S->{$stk}{all_parent_stacks}}){ $stks{$s} = 1; } } elsif($stk_flag eq 'S-1'){ foreach my $s (@{$S->{$stk}{sub_stacks}}){ $stks{$s} = 1; } } elsif($stk_flag eq 'S+1'){ if ($S->{$stk}{parent_stack}){ $stks{$S->{$stk}{parent_stack}} = 1; } } elsif($stk_flag eq 'S-T'){ if (@{$S->{$stk}{sub_stacks}}){ $stks{$S->{$stk}{sub_stacks}[0]} = 1; } } elsif($stk_flag eq 'S-B'){ if (@{$S->{$stk}{sub_stacks}}){ $stks{$S->{$stk}{sub_stacks}[-1]} = 1; } } elsif($stk_flag eq 'S*'){ foreach my $s (keys %$S){ $stks{$s} = 1; } } elsif($stk_flag =~ /^S(\d+\-\d+)$/){ $stks{$1} = 1; } if ($invert){ my %tmp; foreach my $s (keys %$S){ $tmp{$s} = 1 unless $stks{$s}; } return \%tmp; } else{ return \%stks; } } sub GET_MAP_FEATS2{ my @pars = @_; my @return; foreach my $p (@pars){ push @return , (GET_MAP_FEATS(%$p)); } if (wantarray){ return @return; } else{ return \@return; } } sub GET_MAP_FEATS{ my %par = @_; #(map_flag => , layer_stack => ,deep_copy=>) #name,stack,tag $par{layer_stack} = '1-'.$P->{layer_count} unless $par{layer_stack}; $par{deep_copy} = 1 if (!defined $par{deep_copy}); my ($m_name,$m_stack,$m_tag); if ($par{map_flag}){ $par{map_flag} =~ s/\s+//g; ($m_stack,$m_name,$m_tag) = split(':',$par{map_flag}); if ($m_tag){ my @tgs = split(/\s*(\(|\)|\&+|and|or|\|+)\s*/,$m_tag); foreach my $t (@tgs){ if ($t =~ /^\&+$/){ $t = 'and'; } elsif ($t =~ /^\|+$/){ $t = 'or'; } elsif ($t =~ /^\s*([^ ]+)\s*\=\s*([^ ]+)\s*/){ my ($n,$v) = ($1,$2); if ($v =~ /^\[(.*)\]$/){ my $tvv = $1; my @vv = split(/\s*\,\s*/,$tvv); foreach my $tv (@vv){ $tv = '$TAG->{'.$n.'} eq \'' . $tv . '\''; } $t = '('.join(' or ', @vv ).')'; } else{ $t = '$TAG->{' . $1 . '} eq \'' . $2 .'\''; } } else{ $t = '$TAG->{' . $t . '}'; } } $m_tag = join(' ',@tgs); } } if ($par{map_stack}){ $m_stack = $par{map_stack}; } if ($par{map_name}){ $m_name = $par{map_name}; } if ($par{map_tag}){ $m_tag = $par{map_tag}; } if ($m_stack){ if (ref($m_stack) eq 'CODE'){ $m_stack->(%par); } } else{ $m_stack = 'S*'; } my $stks; if (ref($m_stack) eq 'ARRAY'){ foreach my $stk_flag (@$m_stack){ my $t_stks = _parse_stack_flag($par{layer_stack},$stk_flag); foreach my $k (keys %$t_stks){ $stks->{$k} = $t_stks->{$k}; } } } elsif(ref($m_stack) eq 'HASH'){ $stks = $m_stack; } else{ $stks = _parse_stack_flag($par{layer_stack},$m_stack); } return () unless $MAP_DATA->{$m_name}; my @map_feats; foreach my $map_stk (keys %{$MAP_DATA->{$m_name}}){ next unless $stks->{$map_stk}; foreach my $map_pad (@{$MAP_DATA->{$m_name}{$map_stk}}){ my $TAG = $map_pad->{tag}; if ($m_tag){ if (ref($m_tag) eq 'CODE'){ my $ret = $m_tag->(tag=>$TAG); next unless $ret; } else{ my $ret = eval($m_tag); next unless $ret; } } push @map_feats,$map_pad; } } if ($par{deep_copy} and @map_feats){ my $dc = $IKM->deep_copy(\@map_feats); @map_feats = @$dc; } foreach my $item (@map_feats){ $item->{TYPE} = 'MAP_FEAT'; } if (wantarray){ return @map_feats; } else{ return \@map_feats; } } sub _create_symbol{ my ($symbol,$pad_sym) = @_; $GEN->createSymbol(job=>$Job,name=>$symbol); $GEN->openSymbol(job=>$Job,name=>$symbol); $GEN->units(type=>$PAR->{units} || 'inch'); $GEN->addPad(x=>0, y=>0, symbol=>$pad_sym); $GEN->closeSymbol(); $GEN->openStep(job=>$Job,name=>$Step); } sub _shift_size_pad{ my %par = @_; #pad=>,shiftx=>,shift=> my $pad = $par{pad}; my ($point) = TL::GenMath->p_trans({x=>$pad->{x},y=>$pad->{y}},0,'no',$par{shiftx},$par{shifty},$pad); return $point; } sub MAX{ my @sizes = @_; my $size; foreach my $s (@sizes){ $size = $s if (!defined $size or $size < $s); } return $size; } sub MIN{ my @sizes = @_; my $size; foreach my $s (@sizes){ $size = $s if (!defined $size or $size > $s); } return $size; } sub mm2mil{ my $mm = shift; return $mm*100/2.54; } sub mm2inch{ my $mm = shift; return $mm*100/2.54/1000; } sub mil2inch{ my $mil = shift; return $mil/1000; } sub inch2mil{ my $mil = shift; return $mil*1000; } sub inch2mm{ my $inch = shift; return 25.4*$inch; }