=head NAME: DESCRIPTION: Run Overlay 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 : 'font', title : 'Font', type : 'LineEdit', pack : {row:0,column:1}, property : { tool_tip:'genesis中添加文字字体,默认为standard_new' } }, { name : 'default_layer', title : '默认层别', type : 'TextEdit', pack : {row:0,column:1}, property : { tool_tip:'默认层别' }, setter:function(obj,value,self){ obj.setPlainText(value); }, getter:function(obj,self){ return obj.plainText } }, { 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> Run Overlay </p> </body></html> =cut ################################################################################################################# ################################################################################################################# use strict; use utf8; use JSON; use Encode; use Data::Dump 'dump'; use Number::Format 'round'; use_module('TL_GenMath'); use_module("PubFunction"); my $Func = PubFunction->new(); my $Math = TL::GenMath->new(); # my (@Report,$M,$S,$P,$L,$D,$MAP_DATA,@LAYERS,$JOB_PATH,$LAYER_TYPE_LIST,@LAYER_ROWS,$_TMP_LAYER_STK); my ($Job,$Step,$Return) = ($JOB,undef,'finish'); my ($_FEAT_NUM); # $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->{font} = 'standard_new' if(!defined($PAR->{font})); $PAR->{save_job} = 'No' unless $PAR->{save_job}; $PAR->{map_layer} = 'pnl-map' unless $PAR->{map_layer}; $PAR->{map_layer_error} = 'pnl-map-error' unless $PAR->{map_layer_error}; ################################################################################################################# ################################################################################################################# 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; ## if (! $GEN->isLayerExists(job=>$Job,layer=>$PAR->{map_layer} ) ) { $GUI->msgbox(-type=>'error',-text=>"$PAR->{map_layer} 不存在, 请检查!"); return 'Error'; } ## 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{ $version = $GUI->select_from_treeview( -headstock=>'tl-question', -defaultsize=>[200,300], -selectmode=>'single', -title=>__('请选择板框版本'), -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); } ## 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}); $GEN->COM('display_sr',display=>'no'); $GEN->COM('disp_off'); #1.读取map 信息 update_loading("正在读取pnl-map层信息 ,请稍候..",0,position=>'n'); $MAP_DATA = PANEL_MAP_TO_DATA(job=>$Job,step=>$Step,layers=>[$PAR->{map_layer},$PAR->{map_layer_error}],units=>$PAR->{units}); #2.读取MAP传来的值 update_loading("正在读取pnl-map产生的信息文件 ,请稍候..",0,position=>'n'); $JOB_PATH = $GEN->getJobPath(job=>$Job); unless (-f $JOB_PATH.'/user/PNL_map_info'){ $GUI->msgbox('Map信息文件'.$JOB_PATH.'/user/PNL_map_info不存在!'); return 'Error'; } my $map_info = do($JOB_PATH.'/user/PNL_map_info'); $S = $map_info->{S}; $P = $map_info->{P}; $L = $map_info->{L}; $D = $map_info->{D}; $M = $GEN->getMatrix(job=>$Job); delete $M->{$PAR->{map_layer}}; delete $M->{$PAR->{map_layer_error}}; #3.用户选择层 update_loading("选择板框添加层别..",0,position=>'n'); my $default_layer; if (lc($PAR->{default_layer}) eq 'all'){ $default_layer = [keys %$M]; } else{ $default_layer = eval($PAR->{default_layer}); } @LAYERS = $GUI->select_layer( -title=>__('Run Panel Overlay'), -layermatrix=>$M, -selectmode => 'multiple', -default => $default_layer, ); return 'Cancel' unless(@LAYERS); update_loading("开始板框准备工作..",0,position=>'n'); my $db_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"], -where=>{version=>$version,category=>$panel_category,active=>1}, #-order=>'flow_order asc', -order=>"version ASC,parent_id ASC,flow_order ASC", ); foreach my $row (@$db_data){ if ($row->{row_type} eq 'Map Header' or $row->{row_type} eq 'Map Footer' or $row->{row_type} eq 'Map Symbol'){ $row->{row_type} = 'Category'; } push @LAYER_ROWS,$row; } foreach my $stack (values %$S){ my $stk = $stack->{key}; $L->{$stack->{top_layer_num}}{stack} = $stk; $L->{$stack->{top_layer_num}}{layer_side} = 'Top'; $L->{$stack->{bot_layer_num}}{stack} = $stk; $L->{$stack->{bot_layer_num}}{layer_side} = 'Bot'; foreach my $drl (keys %$D){ my $drill = $D->{$drl}; if ($drill->{drl_type} eq 'Laser'){ if ($drill->{drl_start_num} == $stack->{start_num}){ $drill->{stack} = $stk; $drill->{drl_side} = 'Top'; } elsif($drill->{drl_end_num} == $stack->{end_num}){ $drill->{stack} = $stk; $drill->{drl_side} = 'Bot'; } } else{ if ($drill->{drl_start_num} == $stack->{start_num} and $drill->{drl_end_num} == $stack->{end_num}) { $drill->{stack} = $stk; } } } } _EXEC_ROWS(['Public','Overlay Header']); ## foreach my $key(keys %$LAYER_TYPE_LIST){ $LAYER_TYPE_LIST->{$key} = eval($LAYER_TYPE_LIST->{$key}); } ## my $_layer_n = 1;my $_layer_count = scalar(@LAYERS) + 2; foreach my $LAYER (@LAYERS){ my ($LAYER_SIDE,$LAYER_NUM,$LAYER_STACK); $LAYER_NUM = $M->{$LAYER}{layer_num} || $M->{$LAYER}{tl_num}; if ($M->{$LAYER}{drl_start_num} and $M->{$LAYER}{drl_end_num}){ ##core上打镭射增加 if( $P->{laser_on_core} ){ foreach my $stack (sort{$b->{stack_level} <=> $a->{stack_level} || $a->{start_num} <=> $b->{start_num}} values %$S){ if ($M->{$LAYER}{drl_start_num} == $stack->{start_num} and $M->{$LAYER}{drl_end_num} == $stack->{end_num}){ $LAYER_STACK = $stack->{key}; last; } } } ## unless($LAYER_STACK){ foreach my $stack (sort{$b->{stack_level} <=> $a->{stack_level} || $a->{start_num} <=> $b->{start_num}} values %$S){ if ($M->{$LAYER}{drl_start_num} == $stack->{start_num} or $M->{$LAYER}{drl_end_num} == $stack->{end_num}){ $LAYER_STACK = $stack->{key}; last; } } } if (exists $D->{$LAYER_STACK}){ if ($M->{$LAYER}{layer_side}){ $LAYER_SIDE = $M->{$LAYER}{layer_side} eq 'top' ? 'Top' : ($M->{$LAYER}{layer_side} eq 'bottom' ? 'Bot' : ''); } else{ $LAYER_SIDE = $D->{$LAYER_STACK}{drl_side}; } } } elsif(exists $L->{$LAYER_NUM}){ $LAYER_STACK = $L->{$LAYER_NUM}{stack}; $LAYER_SIDE = $L->{$LAYER_NUM}{layer_side}; } else{ $LAYER_STACK = '1-'.$P->{layer_count}; $LAYER_SIDE = $M->{$LAYER}{layer_side} eq 'top' ? 'Top' : ($M->{$LAYER}{layer_side} eq 'bottom' ? 'Bot' : ''); } if(!defined($LAYER_SIDE) and defined($M->{$LAYER}{layer_side})){ $LAYER_SIDE = $M->{$LAYER}{layer_side} eq 'top' ? 'Top' : ($M->{$LAYER}{layer_side} eq 'bottom' ? 'Bot' : ''); } $_TMP_LAYER_STK = $LAYER_STACK; _EXEC_ROWS(['Layer Header'],$LAYER); show_loading("正在创建[${LAYER}]层板框图形...",$_layer_n/$_layer_count,position=>'n'); CREATE_LAYER_OVERLAY(layer=>$LAYER,layer_stack=>$LAYER_STACK,layer_num=>$LAYER_NUM,layer_side=>$LAYER_SIDE); _EXEC_ROWS(['Layer Footer'],$LAYER); $_layer_n++; } $GEN->COM('disp_on'); _EXEC_ROWS(['Overlay Footer']); ## $GEN->clearLayers(); $GEN->affectedLayer( mode=>'all',affected=>'no' ); hide_loading(); #报告 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->COM('filter_reset',filter_name=>'popup'); $GEN->clearHighlight(); $GEN->COM('disp_on'); }; ################################################################################################################# ################################################################################################################# 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 _parse_layer_types{ my $LAYER = shift; my $type_str = shift; my $layer_types = eval($type_str); $layer_types = [keys %$LAYER_TYPE_LIST] unless $layer_types; my $LAYER_TYPES; foreach my $type (@$layer_types){ next unless $LAYER_TYPE_LIST->{$type}; if (ref($LAYER_TYPE_LIST->{$type}) eq 'Regexp'){ $LAYER_TYPES->{$type} = 1 if $LAYER =~ $LAYER_TYPE_LIST->{$type}; } elsif(ref($LAYER_TYPE_LIST->{$type}) eq 'ARRAY'){ foreach my $t (@{$LAYER_TYPE_LIST->{$type}}){ if (lc($t) eq lc($type)){ $LAYER_TYPES->{$type} = 1; last; } } } elsif(ref($LAYER_TYPE_LIST->{$type}) eq 'CODE'){ $LAYER_TYPES->{$type} = 1 if $LAYER_TYPE_LIST->{$type}->(LAYER=>$LAYER,M=>$M,D=>$D,L=>$L,P=>$P); } else{ $LAYER_TYPES->{$type} = 1 if lc($LAYER) eq lc($LAYER_TYPE_LIST->{$type}); } } return $LAYER_TYPES; } sub MAP_TO_LAYER_FEATS { my %par = @_; #(layer=>'',draw_layer=>,parent_id=>) my $LAYER = $par{layer}; my $LAYER_STACK = $par{layer_stack}; my $LAYER_NUM = $par{layer_num}; my $LAYER_SIDE = $par{layer_side}; my $DRAW_LAYER = $par{draw_layer}; $DRAW_LAYER= $par{layer} unless $DRAW_LAYER; my @feats; ## $par{parent_id} = 0 unless $par{parent_id}; ## foreach my $row (@LAYER_ROWS){ #条件 next if $par{parent_id} != $row->{parent_id}; #$GUI->debug(dump($par{parent_id}, $row->{parent_id})); if ($row->{row_type} eq 'Layer'){ #my $ans = $GUI->debug(dump(1111,'---',$LAYER,'---',$row->{layer_type})); #exit unless $ans eq 'ok'; my $LAYER_TYPES = _parse_layer_types($LAYER,$row->{layer_type}); #my $ans = $GUI->debug(dump($LAYER,'---',$LAYER_TYPES,'---',$row->{layer_type})); #exit unless $ans eq 'ok'; next unless $LAYER_TYPES; #$GUI->debug(dump($row->{layer_type}, $LAYER_TYPES)); my $content = eval($row->{content}); if ($@) { print dump($row),"\n"; print dump($@),"\n"; print dump(ref($content)),"\n"; print dump($content),"\n"; $GEN->PAUSE('error'); $GUI->msgbox(-icon=>'error',-text=>"[$row->{row_name}]在${LAYER}上执行错误!\n $@"); exit; } if (ref($content) eq 'CODE'){ $content = $content->(layer=>$LAYER,layer_stack=>$LAYER_STACK,layer_num=>$LAYER_NUM,layer_side=>$LAYER_SIDE,draw_layer=>$DRAW_LAYER); } if (ref($content) eq 'ARRAY' or ref($content) eq 'HASH'){ $content = [$content] unless ref($content) eq 'ARRAY'; foreach my $item (@$content){ if ($item->{feat_type} ){ push @feats,$item; next; } my $map_pads; $item->{layer_stack} = $LAYER_STACK unless defined $item->{layer_stack}; #$item->{layer_flag} = 'S,E' unless $item->{layer_flag}; $item->{layer_num} = $LAYER_NUM unless $item->{layer_num}; if ($item->{side_flag}){ if (uc($item->{side_flag}) eq 'T' or uc($item->{side_flag}) eq 'TOP'){ next unless (uc($LAYER_SIDE) eq 'T' or uc($LAYER_SIDE) eq 'TOP'); } else{ next if (uc($LAYER_SIDE) eq 'T' or uc($LAYER_SIDE) eq 'TOP'); } } if($item->{map_pads}){ $map_pads = delete $item->{map_pads}; } else{ if (ref($item->{condition}) eq 'CODE'){ $item->{condition} = $item->{condition}->(layer=>$LAYER,layer_stack=>$LAYER_STACK,layer_num=>$LAYER_NUM,layer_side=>$LAYER_SIDE,draw_layer=>$DRAW_LAYER); next if (defined $item->{condition} and $item->{condition} == 0); } $map_pads = GET_MAP_FEATS(%$item,deep_copy=>0); } next unless $map_pads; foreach my $map_pad (@$map_pads){ my $tmp = $Func->deep_copy($item); foreach my $k (keys %$tmp){ $tmp->{$k} = $tmp->{$k}->(layer=>$LAYER,layer_stack=>$LAYER_STACK,layer_num=>$LAYER_NUM,layer_side=>$LAYER_SIDE,draw_layer=>$DRAW_LAYER,map_pad_stk=>$map_pad->{stack},map_pad=>$map_pad) if ref($tmp->{$k}) eq 'CODE'; } if ($tmp->{layer_flag}){ next unless _parse_layer_flag($map_pad->{stack},$tmp->{layer_flag},$tmp->{layer_num}); } if (defined $item->{text}){ push @feats,map_feat_to_text(%$tmp,map_pad=>$map_pad); } elsif(defined $item->{xs}){ push @feats,map_feat_to_line(%$tmp,map_pad=>$map_pad); } else{ push @feats,map_feat_to_pad(%$tmp,map_pad=>$map_pad); } } } } } push @feats,MAP_TO_LAYER_FEATS(%par,parent_id=>$row->{id}); } return @feats; }; sub GET_MAP_FEATS{ my %par = @_; #(map_flag => , layer_stack => ,deep_copy=>) #name,stack,tag $par{layer_stack} = $_TMP_LAYER_STK 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 = $Func->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 _EXEC_ROWS { my $row_type = shift; my $LAYER = shift; my $parent_id = shift || 0; my %row_types; foreach my $t (@$row_type,'Category'){ $row_types{$t} = 1; } foreach my $row (@LAYER_ROWS){ next if $row->{parent_id} ne $parent_id; if ($row->{row_type} ne 'Category' and $row_types{$row->{row_type}}){ if (defined $LAYER){ my $LAYER_TYPES = _parse_layer_types($LAYER,$row->{layer_type}); next unless $LAYER_TYPES; } my $content = eval($row->{content}); if ($@) { $GUI->msgbox(-icon=>'error',-text=>"[$row->{row_name}]在${LAYER}上执行错误!\n $@"); return; } if (ref($content) eq 'CODE'){ $content->(layer=>$LAYER); } } _EXEC_ROWS($row_type,$LAYER,$row->{id}); } return ; }; sub map_feat_to_pad { my %par = @_;#(map_pad=>{x=>,y=>,angle=>,mirror=>}) $par{nx} = 1 unless $par{nx}; $par{ny} = 1 unless $par{ny}; $par{dx} = 0 unless $par{dx}; $par{dy} = 0 unless $par{dy}; $par{sx} = 0 unless $par{sx}; $par{sy} = 0 unless $par{sy}; my @pads; foreach my $num_nx (1..$par{nx}){ foreach my $num_ny (1..$par{ny}){ #偏移 my $pad; my ($dx_shift,$dy_shift) = (($num_nx-1)*$par{dx},($num_ny-1)*$par{dy}); $pad->{feat_type} = 'pad'; $pad->{x} = $par{map_pad}{x} + $par{sx} + $dx_shift; $pad->{y} = $par{map_pad}{y} + $par{sy} + $dy_shift; $pad->{angle} = $par{angle} || 0; $pad->{mirror} = $par{mirror} || 'no'; $pad->{polarity} = $par{polarity} || 'positive'; $pad->{symbol} = $par{symbol}; $pad->{priority} = $par{priority}; $pad->{num} = $_FEAT_NUM++; if ($par{attributes}){ if (ref($par{attributes}) eq 'ARRAY'){ push @{$pad->{attributes}},@{$par{attributes}}; } else{ push @{$pad->{attributes}},$par{attributes}; } } push @{$pad->{attributes}},@{$par{map_pad}{attributes}}; push @pads,$pad; } } return TL::GenMath->p_trans({x=>$par{map_pad}{x},y=>$par{map_pad}{y}},$par{map_pad}{angle},$par{map_pad}{mirror},0,0,@pads); } sub map_feat_to_line { my %par = @_;#(map_pad=>{x=>,y=>,angle=>,mirror=>}) $par{nx} = 1 unless $par{nx}; $par{ny} = 1 unless $par{ny}; $par{dx} = 0 unless $par{dx}; $par{dy} = 0 unless $par{dy}; $par{xs} = 0 unless $par{xs}; $par{ys} = 0 unless $par{ys}; $par{xe} = 0 unless $par{xe}; $par{ye} = 0 unless $par{ye}; my @lines; foreach my $num_nx (1..$par{nx}){ foreach my $num_ny (1..$par{ny}){ #偏移 my $line; my ($dx_shift,$dy_shift) = (($num_nx-1)*$par{dx},($num_ny-1)*$par{dy}); $line->{feat_type} = 'line'; $line->{xs} = $par{map_pad}{x} + $par{xs} + $dx_shift; $line->{ys} = $par{map_pad}{y} + $par{ys} + $dy_shift; $line->{xe} = $par{map_pad}{x} + $par{xe} + $dx_shift; $line->{ye} = $par{map_pad}{y} + $par{ye} + $dy_shift; $line->{polarity} = $par{polarity} || 'positive'; $line->{symbol} = $par{symbol}; $line->{priority} = $par{priority}; $line->{num} = $_FEAT_NUM++; if ($par{attributes}){ if (ref($par{attributes}) eq 'ARRAY'){ push @{$line->{attributes}},@{$par{attributes}}; } else{ push @{$line->{attributes}},$par{attributes}; } } push @{$line->{attributes}},@{$par{map_pad}{attributes}}; push @lines,$line; } } foreach my $line (@lines){ my ($ps,$pe) = TL::GenMath->p_trans({x=>$par{map_pad}{x},y=>$par{map_pad}{y}},$par{map_pad}{angle},$par{map_pad}{mirror},0,0,{x=>$line->{xs},y=>$line->{ys}},{x=>$line->{xe},y=>$line->{ye}}); ($line->{xs},$line->{ys}) = ($ps->{x},$ps->{y}); ($line->{xe},$line->{ye}) = ($pe->{x},$pe->{y}); } return @lines; } sub map_feat_to_text{ my %par = @_; $par{sx} = 0 unless $par{sx}; $par{sy} = 0 unless $par{sy}; my $text; $text->{feat_type} = 'text'; $text->{x} = $par{map_pad}{x} + $par{sx}; $text->{y} = $par{map_pad}{y} + $par{sy}; $text->{angle} = $par{angle} || 0; $text->{mirror} = $par{mirror} || 'no'; $text->{polarity} = $par{polarity} || 'positive'; $text->{text} = $par{text}; $text->{x_size} = $par{x_size} || 0.15; $text->{y_size} = $par{y_size} || 0.15; $text->{line_width} = $par{line_width} || 10; $text->{anchor} = $par{anchor} || 'center'; $text->{trans_anchor} = $par{trans_anchor} ; $text->{fontname} = $par{fontname} || $PAR->{font}; $text->{type} = $par{type}; $text->{text_length} = $par{text_length}; $text->{priority} = $par{priority}; $text->{num} = $_FEAT_NUM++; if ($par{attributes}){ if (ref($par{attributes}) eq 'ARRAY'){ push @{$text->{attributes}},@{$par{attributes}}; } else{ push @{$text->{attributes}},$par{attributes}; } } push @{$text->{attributes}},@{$par{map_pad}{attributes}}; my ($tmp) = TL::GenMath->p_trans({x=>$par{map_pad}{x},y=>$par{map_pad}{y}},$par{map_pad}{angle},'no',0,0,$text); my $mirror; if ($par{map_pad}{mirror} eq 'yes'){ if ($tmp->{mirror} eq 'no'){ $mirror = 'yes'; } else{ $mirror= 'no'; } } else{ $mirror = $tmp->{mirror}; } if ($mirror eq 'yes' or $mirror eq 'x') { if ($tmp->{angle} == 90 or $tmp->{angle} == 270){ $tmp->{angle} += 180; } } elsif($mirror eq 'y'){ if ($tmp->{angle} == 0 or $tmp->{angle} == 180){ $tmp->{angle} += 180; } } $tmp->{angle} = $tmp->{angle} % 360; $tmp->{mirror} = (!$mirror or $mirror eq 'no')? 'no' : 'yes'; return ($tmp); } sub GET_FLAG_STACK{ my ($stk,$stk_flag) = @_; my $stks = _parse_stack_flag($stk,$stk_flag); my @retstks = sort {$S->{$b}{stack_level} <=> $S->{$a}{stack_level} ||$S->{$a}{start_num} <=> $S->{$a}{end_num}} keys %$stks; if (wantarray){ return @retstks; } else{ return $retstks[0]; } } sub _parse_layer_flag{ my ($stk,$layer_flag,$layer_number) = @_; $layer_flag =~ s/\s+//g; $layer_flag = 'S,E' if $layer_flag eq 'SE'; my $stack = $S->{$stk}; my $stk_start_num = $stack->{top_layer_num} || 1; my $stk_end_num = $stack->{bot_layer_num} || $P->{layer_count}; my @list = split(/\,+/,$layer_flag); foreach my $item (@list){ my ($from,$to); if ($item =~ /^([^.]*)\.+([^.]*)$/){ ($from,$to) = ($1,$2); } else{ $from = $to = $item; } $from = 1 unless $from; $to = $P->{layer_count} unless $to; foreach my $flag ($from,$to){ if ($flag =~ /^(S|E)([+-]?\d+)?/){ my ($se,$n) = ($1,$2); $n = 0 unless $n; if ($se eq 'S'){ $flag = $stk_start_num - $n; } else{ $flag = $stk_end_num + $n; } } } return 1 if ($layer_number >= $from and $layer_number <= $to); } return 0; } #获取Stack中第几层的层号 sub GET_STK_NUM_LAYER{ my ($stk,$num) = @_; return unless $S->{$stk}; my $stack = $S->{$stk}; if ($num == 1){ return $stack->{start_num}; } elsif($num == -1){ return $stack->{end_num}; } elsif($num > 1){ my $layer_num = int($stack->{start_num}) + $num - 1; return if $layer_num > $stack->{end_num}; return $layer_num; } elsif($num < 0){ my $layer_num = int($stack->{end_num}) - $num + 1; return if $layer_num < $stack->{start_num}; return $layer_num; } } #获取层位于压合中的第几层 sub GET_LAYER_STK_NUM { my ($layer_num,$stk) = @_; return unless $S->{$stk}; my $stack = $S->{$stk}; my $lyr_num = int($layer_num); return if ($lyr_num < int($stack->{start_num}) or $lyr_num > int($stack->{end_num})); my $na = $lyr_num - int($stack->{start_num}) + 1; my $nb = $lyr_num - int($stack->{end_num}) - 1; if (wantarray){ return ($na,$nb); } else{ return $na; } } sub _parse_stack_flag{ my ($stk,$stk_flag) = @_; my %stks; my $invert; $stk_flag = 'S*' unless $stk_flag; if ($stk_flag =~ /^\!/){ $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 CREATE_LAYER_OVERLAY{ my %par = @_; #(layer=>'',draw_layer=>,invert=>) my $LAYER = $par{layer}; my $LAYER_STACK = $par{layer_stack}; my $LAYER_NUM = $par{layer_num}; my $LAYER_SIDE = $par{layer_side}; my $DRAW_LAYER = $par{draw_layer}; $DRAW_LAYER= $par{layer} unless $DRAW_LAYER; #$GEN->openStep(job=>$Job,name=>$Step); $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>[$DRAW_LAYER],clear_before=>'yes'); $GEN->COM('sel_all_feat'); $GEN->selDelete(); my @feats = MAP_TO_LAYER_FEATS(%par); #$GEN->PAUSE("feats === \n ".dump(\@feats)); ADD_FEATS_ON_LAYER($DRAW_LAYER,\@feats,invert=>$par{invert}); } sub ADD_FEATS_ON_LAYER{ my ($DRAW_LAYER,$FEATS,%par) = @_; #$GEN->openStep(job=>$Job,name=>$Step); $GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>[$DRAW_LAYER],clear_before=>'yes'); $GEN->selDelete() if $GEN->getSelectCount(); my $polarity_invert = {'positive'=>'negative','negative'=>'positive'}; foreach my $feat (sort{$b->{priority} <=> $a->{priority} || $a->{num} <=> $b->{num}} @$FEATS){ my %tmp = %$feat; my $type = delete $tmp{feat_type}; delete $tmp{priority}; delete $tmp{num}; $tmp{polarity} = 'positive' unless $tmp{polarity}; if ($par{invert}){ $tmp{polarity} = $polarity_invert->{$tmp{polarity}}; } if ($type eq 'pad'){ $GEN->addPad(%tmp); } elsif($type eq 'text'){ $GEN->addText(%tmp); } elsif($type eq 'line'){ $GEN->addLine(%tmp) } elsif($type eq 'rect'){ $GEN->addRectangle(%tmp); } elsif($type eq 'poly'){ $GEN->addPolygon(%tmp); } } $GEN->clearLayers(); $GEN->affectedLayer(mode=>'all',affected=>'no'); } sub PANEL_MAP_TO_DATA{ my %par = @_; $par{units} = 'inch' if(!defined($par{units})); my $MapData; foreach my $layer (@{$par{layers}}){ next unless ($GEN->isLayerExists(job=>$par{job},layer=>$layer)); my @feats = $GEN->getFeatures(job=>$par{job},step=>$par{step},layer=>$layer,units=>$par{units}); foreach my $item (@feats){ next if $item->{type} ne 'pad'; foreach my $attr (@{$item->{attributes}}){ next if($attr !~ /^tl_string\=(.*)/); $attr = $1; next if($attr !~ /^S/); my @attrs = split(':',$attr); my $stack = shift @attrs; $stack =~ s/^S//; my $name = shift @attrs; my %tags; foreach my $tag (@attrs){ if ($tag =~ /^(.*)\=(.*)$/){ $tags{$1} = $2; } else{ $tags{$tag} = 1; } } push @{$MapData->{$name}{$stack}},{ attributes => [{attribute=>'tl_string',text=>$attr}], x => $item->{x}, y => $item->{y}, symbol => $item->{symbol}, angle => $item->{angle}, mirror => $item->{mirror}, stack => $stack, name => $name, tag => \%tags } } } } return $MapData; } 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; } 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; }