=head
 NAME: TL_PUB_create_impedance_coupon
 DESCRIPTION: 绘制阻抗图形
 PARAMETER:
	[
		
	]
	
 VERSION_HISTORY:
	V1.00 2011-12-03 Tony Guo
		New Version
	V1.01 2013-06-09 Tony Guo
		Fixed bug when coplanar and normal impeance in same test coupon		
	V1.02 2016-11-25 Bill Li
		获取到的线宽间距等单位转换um2mil.
	V1.03 2016-11-25 Cody Yu
		1.阻抗条长度和宽度取出来，不用/25.4
	V1.04 2016-12-06 Cody Yu
		1.阻抗线增加补偿
	V2.00 2017-06-22 Tomy
		1.转为EPQ版本，inch|mm用于设定阻抗表单存的coupon条size单位 mm时要除以25.4
	V2.01 2017-09-21 Cody
		1.文件存储改为string存储
	V2.02 2017-09-22 Tomy
		1.增加挡墨和防焊开窗，钻孔层定为dir层
	V3.00 2017-10-26 Cody
		1.产品升级到V6
	V3.01 2017-12-14 Shyer
		1.coupon线补偿带小数位修复
		2.阻抗条尺寸公英制转换小数位异常修复
	V3.02 2017-12-15 Shyer
		1.共面阻抗铜面增加补偿（同线宽补偿）
	V3.03 2018-01-08 Tomy
		1._um2mil公制转英制取消取三位小数
	V3.04 2019-04-16 Shyer
		1.新增单层body text位置获取
	V3.05 2020-07-29 Kurri
		1.body text修改为仅外层Top面添加
		2.档点层别名支持做${layer_count}变量替换
	V3.06 2020-11-30 Kurri
		1.档点层改为正片
		
 HELP:
  
=cut

use strict;
use utf8;
use Encode;
use JSON;
use Data::Dump 'dump';
my ($Job,$LayerCount,$Return,$WarningMsg,$units);
$units = "inch";
#$units = "mm";
use_module("PubFunction");
my $F = PubFunction->new();

my $db_units = 'um'; # 数据库中存的线宽间距的单位 (um|mil)
my $coupon_size_units='mm';  #inch|mm用于设定阻抗表单存的coupon条size单位 mm时要除以25.4


try{
	unless ($JOB){
		$JOB = $GUI->select_job(-title=>'请选择料号',-joblist=>$IKM->select_fieldarray(-table=>'pdm_job',-field=>'jobname',-order=>'id DESC'));
		return 'Cancel' unless $JOB;
	};
	$JOB_ID = $IKM->get_job_id($JOB) unless $JOB_ID;
	$Job = lc($JOB) unless $Job ;
	##
	if (! $GEN->isJobExists(job=>$Job) ){
        $GUI->msgbox(-icon=>'error',-text=>"料号 $Job 在Genesis中不存在, 请检查!");
        return 'Error';
    }
	##
	$Return = 'Done';
	use_module('ImpCouponData');

	#获取数据库里的料号层数
	my $dbLayerCount = $IKM->get_jobinfo(-jobinfo=>'layer_count',-jobid=>$JOB_ID);
	#$dbLayerCount = 10;
	#检查DB上的层总数是否与genesis一致
	$LayerCount = $GEN->getLayerCount(job=>$Job);
	if ( $dbLayerCount and $LayerCount != $dbLayerCount){
		return 'Error' if ($GUI->confirm('Genesis料号里的板层数与数据内不一致,你确定要继续吗?') eq 'no');
	}
	#$LayerCount = 10;
	#选择需要运行的coupon
	my $imps = $IKM->select_arrayhash(-table=>'pdm_job_imp',-field=>['target_impedance','coupon_name'],-where=>{job_id=>$JOB_ID});
	unless(@$imps){
		$GUI->msgbox(-icon=>'error',-text=>"料号 $Job 中没有阻抗信息, 请检查是否有录入!");
        return 'Error';
	}
	my (@coupon_list,@sel_coupons);
	my %coupons;
	foreach my $imp (@$imps){
		my @cp_names = split(',',$imp->{coupon_name});
		foreach my $cp_name (@cp_names){
			$coupons{$cp_name}{$imp->{target_impedance}} = 1;
		}
		
	}
	foreach my $cp (sort keys %coupons){
		push @coupon_list,$cp,uc($cp);
		#push @coupon_list,$cp,'< '.$cp.' >  '.join(' | ',sort{$a <=> $b} keys %{$coupons{$cp}});
		push @sel_coupons,$cp;
	}
	
	my %vform = $GUI->show_form(
		-defaultsize=>[350,400],
		-title => '请选择阻抗条',
		-items => [
			{name=>'title1',type=>'frame',property=>{}},
			{
				name => 'coupons',
				type => 'checkbox',
				property => {
					tl_list => \@coupon_list,
					tl_columns => 1,
				},
				value => \@sel_coupons,
				
			},
			{
				name => 'btn',
				label => '',
				type => 'label',
				button_position => 'left',
				buttons => [
					{name=>'btn_sel_all',label=>'全选',command=>sub{
							my %par = @_;
							$par{formpanel}->set_value('coupons',\@sel_coupons);
					}},
					{name=>'btn_unsel_all',label=>'取消全选',command=>sub{
							my %par = @_;
							$par{formpanel}->set_value('coupons',undef);
					}},
				]
			},
			{name=>'title2',type=>'vbox',property=>{},overback=>1},
			
			{
				name => 'show_form',
				label => '显示参数确认界面',
				type => 'radio',
				property => {
					tl_list => ['yes'=>'YES','no'=>'NO'],
					tl_columns => 3,
				},
				value => 'no',
			}
		]
	);
	return 'Cancel' unless %vform;
	@sel_coupons = @{$vform{coupons}}; 

	return 'Cancel' unless @sel_coupons;
	
	#查找HDI钻孔层
	my $matrix = $GEN->getMatrix(job=>$Job,type=>'hash');
	foreach my $cp_name (sort @sel_coupons){
		my $COUPON_DATA;
		$COUPON_DATA->{coupon_name} = $cp_name;
		#foreach my $info ('coupon_length','coupon_width','coupon_template','coupon_position','coupon_layout_parameter'){
			#$COUPON_DATA->{coupon_template} = $IKM->get_layerinfo(-jobid=>$JOB_ID,-layer=>$cp_name,-layerinfo=>'coupon_template_name');
		#}
		$COUPON_DATA->{coupon_template} = 'coupon';   # FOR test
		#$IKM->command('function(){APP.setDebugMode(5)}',{},0);
		my $cfg = $IKM->select_value(-table=>'pub_conf',-field=>'json_data',-where=>{path => 'pdm/impedance_coupon_template'});
		#$GUI->msgbox(-text=>dump($cfg));
		# 转换配置 json2perl
		#my $file = ${ENV}{GENESIS_TMP}.'/impedance_coupon_template';
		#$file = '>'.$file;
		#open(MF,$file);
		#print MF $cfg;
		#close MF;
		#$file = ${ENV}{GENESIS_TMP}.'/impedance_coupon_template';
		#my $_data = $F->prase_file_json2perl_hash(file=>$file);
		my $_data = $F->prase_file_json2perl_hash(string=>$cfg);
		#unlink $file;
		
		#my $template_value = eval($cfg);
		my $template_value = $_data;
		foreach my $item (keys %$template_value){
			$COUPON_DATA->{$item}  = $template_value->{$item};
		}
		my $layout_param = $IKM->get_layerinfo(-jobid=>$JOB_ID,-layer=>$cp_name,-layerinfo=>'coupon_layout_parameter');
		if ($layout_param){
			$layout_param = eval($layout_param);
			foreach my $k (keys %{$layout_param}){
				$COUPON_DATA->{$k} = $layout_param->{$k} if defined $layout_param->{$k};
			}
		}
		
		$COUPON_DATA->{coupon_position} = $IKM->get_layerinfo(-jobid=>$JOB_ID,-layer=>$cp_name,-layerinfo=>'coupon_on_step');
		$COUPON_DATA->{fixed_fields}{coupon_position} = 1;
		 
		my $cp_length = $IKM->get_layerinfo(-jobid=>$JOB_ID,-layer=>$cp_name,-layerinfo=>'coupon_length');
		my $cp_length_org = eval($cp_length);
		if($coupon_size_units eq 'mm'){
			$cp_length = sprintf("%.3f",$cp_length/25.4);
		}
		#$cp_length = $cp_length/25.4;
		if ($cp_length){
			$COUPON_DATA->{coupon_length} = $cp_length;
			$COUPON_DATA->{coupon_length_org} = $cp_length_org;
			$COUPON_DATA->{auto_enlarge_coupon_length} = 'no';
			$COUPON_DATA->{fixed_fields}{coupon_length} = 1;
			$COUPON_DATA->{fixed_fields}{auto_enlarge_coupon_length} = 1;
		}
		
		my $cp_width = $IKM->get_layerinfo(-jobid=>$JOB_ID,-layer=>$cp_name,-layerinfo=>'coupon_width');
		my $cp_width_org = eval($cp_width);
		if($coupon_size_units eq 'mm'){
			$cp_width = sprintf("%.3f",$cp_width/25.4);
		}
		#$cp_width = $cp_width/25.4;
		if ($cp_width){
			$COUPON_DATA->{coupon_body_width} = $COUPON_DATA->{coupon_header_width} = $cp_width;
			$COUPON_DATA->{coupon_body_width_org} = $COUPON_DATA->{coupon_header_width_org} = $cp_width_org;
			$COUPON_DATA->{auto_enlarge_coupon_header_width} = 'no';
			$COUPON_DATA->{auto_enlarge_coupon_body_width} = 'no';
			$COUPON_DATA->{fixed_fields}{coupon_body_width} = 1;
			$COUPON_DATA->{fixed_fields}{coupon_header_width} = 1;
			$COUPON_DATA->{fixed_fields}{auto_enlarge_coupon_header_width} = 1;
			$COUPON_DATA->{fixed_fields}{auto_enlarge_coupon_header_width} = 1;
		}
		
		my $all_imps = $IKM->select_arrayhash(-table=>'pdm_job_imp',-field=>['*'],-where=>{job_id=>$JOB_ID});
		foreach my $imp (@$all_imps){
			$imp->{signal1} = imp_layernum2tlname($imp->{signal1});
			$imp->{signal2} = imp_layernum2tlname($imp->{signal2});
			$imp->{reference1} = imp_layernum2tlname($imp->{reference1});
			$imp->{reference2} = imp_layernum2tlname($imp->{reference2});
			$imp->{id} = $imp->{uuid};
			my @cp_names = split(',',$imp->{coupon_name});
			foreach my $cp_nm (@cp_names){
				if ($cp_name eq $cp_nm){
					if ($db_units eq 'um') {
						# 数据转换 um2mil by Bill 20161125
						$imp->{org_line_width1} = sprintf("%.1f",_um2mil($imp->{org_line_width1}));
						$imp->{org_spacing} = sprintf("%.1f",_um2mil($imp->{org_spacing}));
						$imp->{line_width1} = sprintf("%.1f",_um2mil($imp->{line_width1})); #1
						$imp->{line_width1_adjust_max} = sprintf("%.1f",_um2mil($imp->{line_width1_adjust_max}));
						$imp->{line_width1_adjust_min} = sprintf("%.1f",_um2mil($imp->{line_width1_adjust_min}));
						$imp->{spacing} = sprintf("%.1f",_um2mil($imp->{spacing})); #1
						#$imp->{target_impedance_max} = _um2mil($imp->{target_impedance_max});
						#$imp->{target_impedance_min} = _um2mil($imp->{target_impedance_min});
						$imp->{target_impedance_max} = $imp->{target_impedance_max};
						$imp->{target_impedance_min} =$imp->{target_impedance_min};
						$imp->{test_line_length} = sprintf("%.1f",_um2mil($imp->{test_line_length}));
						#添加一个 coplanar_spacing 转换 Tomy 20170621
						$imp->{coplanar_spacing} = sprintf("%.1f",_um2mil($imp->{coplanar_spacing})); #1
					}
					push @{$COUPON_DATA->{impedances}},$imp;
				}
			}
		}
		$COUPON_DATA->{GEN} = $GEN;
		$COUPON_DATA->{job_id} = $JOB_ID;
		$COUPON_DATA->{job_name} = $JOB;
		my $coupon_object = Top::ImpCouponData->new(-IKM=>$IKM);
		$coupon_object->set_coupon_data($COUPON_DATA);
		$coupon_object->set_layer_count($LayerCount);
		$coupon_object->set_matrix($matrix);
		$coupon_object->coupon_to_layer();
		if ($vform{show_form} eq 'yes' or !$COUPON_DATA->{coupon_template}){
			return 'Cancel' unless $coupon_object->show_coupon_form();
		}
		$coupon_object->convert_units();
		$coupon_object->convert_matrix();
		$coupon_object->analysis_group();
		$coupon_object->line_copmensation();
		$coupon_object->group_left_right();
		$coupon_object->init_pad_position();
		$coupon_object->adjust_coupon_length();
		$coupon_object->init_line_y_sequence();
		$coupon_object->calc_line_y();
		$coupon_object->layout_header_lines();
		$coupon_object->header_text_position();
		$coupon_object->adjust_coupon_width();
		
		my %gen_layer;
		foreach my $item (keys %{$COUPON_DATA->{matrix}}){
			if ($COUPON_DATA->{matrix}{$item}{tl_name}){
				$gen_layer{$COUPON_DATA->{matrix}{$item}{tl_name}} = $item;
			}
		}
		my $step = lc($cp_name);
		if ($GEN->isStepExists(job=>$Job,step=>$step)){
			return 'Cancel' unless ($GUI->confirm("Step $step 已经存在,确定要覆盖它吗?") eq 'yes');
			my @boardLayers;
			foreach my $item (keys %$matrix){
				if ($matrix->{$item}{context} eq 'board'){
					push @boardLayers,$item;
				}
			}
			$GEN->openStep(job=>$Job,name=>$step);
			$GEN->clearLayers();
			$GEN->affectedLayer(mode=>'all',affected=>'yes');
			$GEN->COM('sel_all_feat');
			$GEN->selDelete();
		}
		else{
			$GEN->createStep(job=>$Job,name=>$step);
			$GEN->openStep(job=>$Job,name=>$step);
		}
		
		if ($COUPON_DATA->{coupon_layout_path} eq 'customize'){
			$GEN->clearLayers();
			$GEN->affectedLayer(mode=>'all',affected=>'no');
			$GEN->PAUSE('Select Coupon Layout Path');
			my $work_layer =$GEN->getWorkLayer();
			
			my @feats = $GEN->getFeatures(job=>$Job,step=>$step,layer=>$work_layer,options=>'select',units=>'inch') if $work_layer;
			
			if (@feats){
				@feats = opt_lines(@feats);
				
				my $ps = TL::GenMath->calc_point_on_line($feats[0],$COUPON_DATA->{'left_header_area_rect'}{xmax} - $COUPON_DATA->{'left_header_area_rect'}{xmin});
				my $pe = TL::GenMath->calc_point_on_line({xs=>$feats[-1]{xe},ys=>$feats[-1]{ye},xe=>$feats[-1]{xs},ye=>$feats[-1]{ys}},$COUPON_DATA->{'right_header_area_rect'}{xmax} - $COUPON_DATA->{'right_header_area_rect'}{xmin});
				($feats[0]{xs},$feats[0]{ys}) = ($ps->{x},$ps->{y});
				($feats[-1]{xe},$feats[-1]{ye}) = ($pe->{x},$pe->{y});
				
				
				my @line_path = ({x=>$feats[0]{xs},y=>$feats[0]{ys}});
				foreach my $feat (@feats){
					my $tmp = {x=>$feat->{xe},y=>$feat->{ye}};
					if ($feat->{type} eq 'arc'){
						@{$tmp}{'xc','yc','direction'} = @{$feat}{'xc','yc','direction'};
					}
					push @line_path,$tmp;
				}
				$coupon_object->{COUPON_DATA}{line_path} = \@line_path;
			}
		}
		$coupon_object->layout_path_lines();
		$coupon_object->body_text_position();
		$coupon_object->layer_body_text_position();
		$coupon_object->coplanar_hole_position();
		
		#$GUI->debug(dump($COUPON_DATA));
		$GEN->COM('disp_off');
		#$GEN->COM('disp_on');
		$GEN->clearLayers();
		$GEN->affectedLayer(mode=>'all',affected=>'no');
		$GEN->units(type=>$units);
		
		#创建Profile
		my ($ShiftX,$ShiftY) = (-$COUPON_DATA->{left_down_zero_pad}{x},-$COUPON_DATA->{left_down_zero_pad}{y});
		
		my $trans;
		$trans->{left}{angle} = 360-$COUPON_DATA->{left_header_transform}{angle};
		$trans->{left}{angle} -= 360 if $trans->{left}{angle} >= 360;
		$trans->{left}{x_anchor} = $COUPON_DATA->{left_header_transform}{x} + $ShiftX;
		$trans->{left}{y_anchor} = $COUPON_DATA->{left_header_transform}{y} + $ShiftY;
		
		$trans->{right}{angle} = 360-$COUPON_DATA->{right_header_transform}{angle};
		$trans->{right}{angle} -= 360 if $trans->{right}{angle} >= 360;
		$trans->{right}{x_anchor} = $COUPON_DATA->{right_header_transform}{x} + $ShiftX;
		$trans->{right}{y_anchor} = $COUPON_DATA->{right_header_transform}{y} + $ShiftY;
		
		my $tmp_layer = 'tl_script_tmp_layer';
		if ($COUPON_DATA->{coupon_layout_path} eq 'customize'){
			$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
			$GEN->createLayer(job=>$Job,layer=>$tmp_layer,context=>'misc',type=>'signal');
			$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_layer,clear_before=>'yes');
			my ($xs,$ys) = ($COUPON_DATA->{center_path_lines}[0]{x},$COUPON_DATA->{center_path_lines}[0]{y});
			my $sym = 'r'.($COUPON_DATA->{coupon_body_width}*1000);
			foreach my $n (1..scalar(@{$COUPON_DATA->{center_path_lines}})-1){
				my $it = $COUPON_DATA->{center_path_lines}[$n];
				if ($it->{direction}){
					$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>$sym);
				}
				else{
					$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>$sym);
				}
				($xs,$ys) = ($it->{x},$it->{y});
			}
			my $clip_w = $COUPON_DATA->{coupon_body_width} + 0.0002;
			$GEN->addPad(x=>$COUPON_DATA->{left_zero_pad}{x}-$clip_w/2+$ShiftX,y=>$COUPON_DATA->{left_zero_pad}{y}+$ShiftY,symbol=>'s'.($clip_w*1000),
						 polarity=>'negative',attributes=>{attribute=>'.string',text=>'left_side'});
			$GEN->addPad(x=>$COUPON_DATA->{right_zero_pad}{x}+$clip_w/2+$ShiftX,y=>$COUPON_DATA->{right_zero_pad}{y}+$ShiftY,symbol=>'s'.($clip_w*1000),
						 polarity=>'negative',attributes=>{attribute=>'.string',text=>'right_side'});
			
			foreach my $lr ('left','right'){
				$GEN->addRectangle(x1=>$COUPON_DATA->{$lr.'_header_area_rect'}{xmin}+$ShiftX,y1=>$COUPON_DATA->{$lr.'_header_area_rect'}{ymin}+$ShiftY,
								   x2=>$COUPON_DATA->{$lr.'_header_area_rect'}{xmax}+$ShiftX,y2=>$COUPON_DATA->{$lr.'_header_area_rect'}{ymax}+$ShiftY,
								   attributes=>{attribute=>'.string',text=>$lr.'_side'}
								   ) if ($COUPON_DATA->{$lr.'_header_area_rect'});
			}
			foreach my $lr ('left','right'){
				if ($trans->{$lr}{angle}){
					$GEN->selClearFeature();
					$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_side'}]);
					$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) ;
				}
			}
			$GEN->COM('sel_all_feat');
			$GEN->selContourize();
			$GEN->COM('sel_all_feat');
			$GEN->COM('sel_surf2outline',width=>0.1);
			$GEN->COM('sel_all_feat');
			
			$GEN->COM('sel_create_profile');
			$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
		}
		else{
			if($coupon_size_units eq 'mm'){
				$GEN->units(type=>$coupon_size_units);
				$GEN->panelSize(width=>$COUPON_DATA->{coupon_length_org},height=>$COUPON_DATA->{coupon_body_width_org});
				$GEN->units(type=>$units);
			}else{
				$GEN->panelSize(width=>$COUPON_DATA->{coupon_length},height=>$COUPON_DATA->{coupon_body_width});
			}
			
		}
			
		my $outer_tpad_sym = $COUPON_DATA->{outer_tpad_shape} . $COUPON_DATA->{pad_size};
		my $inner_tpad_sym = $COUPON_DATA->{inner_tpad_shape} . $COUPON_DATA->{pad_size};
		my $outer_gpad_sym = $COUPON_DATA->{outer_gpad_shape} . $COUPON_DATA->{pad_size};
		my $inner_gpad_sym = $COUPON_DATA->{inner_gpad_shape} . $COUPON_DATA->{pad_size};
		
		my $outer_tpad_clear_sym = $COUPON_DATA->{outer_tpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{outer_pad2copper} * 2);
		my $inner_tpad_clear_sym = $COUPON_DATA->{inner_tpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{inner_pad2copper} * 2);
		my $outer_gpad_clear_sym = $COUPON_DATA->{outer_gpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{outer_pad2copper} * 2);
		my $inner_gpad_clear_sym = $COUPON_DATA->{inner_gpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{inner_pad2copper} * 2);
		
		my $outer_tdrl_clear_sym = $COUPON_DATA->{outer_tpad_shape} . ($COUPON_DATA->{hole_size} + $COUPON_DATA->{drill2copper} * 2);
		my $inner_tdrl_clear_sym = $COUPON_DATA->{inner_tpad_shape} . ($COUPON_DATA->{hole_size} + $COUPON_DATA->{drill2copper} * 2);
		my $outer_gdrl_clear_sym = $COUPON_DATA->{outer_gpad_shape} . ($COUPON_DATA->{hole_size} + $COUPON_DATA->{drill2copper} * 2);
		my $inner_gdrl_clear_sym = $COUPON_DATA->{inner_gpad_shape} . ($COUPON_DATA->{hole_size} + $COUPON_DATA->{drill2copper} * 2);
		
		#patch_ref_sym #填补影响层上漏出线路时用
		my $max_clear = (sort {$b <=> $a} ($COUPON_DATA->{pad_size} + 2*$COUPON_DATA->{outer_pad2copper}, $COUPON_DATA->{pad_size} + 2*$COUPON_DATA->{inner_pad2copper}, $COUPON_DATA->{hole_size} + 2*$COUPON_DATA->{drill2copper}))[0] + 2;
		my $outer_patch_ref_clear_sym = $COUPON_DATA->{outer_tpad_shape} . $max_clear;
		my $inner_patch_ref_clear_sym = $COUPON_DATA->{outer_tpad_shape} . $max_clear;
		
		
		my $tmp_size = ($COUPON_DATA->{pad_size} + $COUPON_DATA->{outer_pad2copper} * 2);
		my $outer_gpad_thermal_sym = $COUPON_DATA->{outer_gpad_thermal};
		$outer_gpad_thermal_sym =~ s/\$\{OUT\}/$tmp_size/;
		$tmp_size = $COUPON_DATA->{pad_size};
		$outer_gpad_thermal_sym =~ s/\$\{IN\}/$tmp_size/;
		$tmp_size = ($COUPON_DATA->{pad_size} + $COUPON_DATA->{inner_pad2copper} * 2);
		my $inner_gpad_thermal_sym = $COUPON_DATA->{inner_gpad_thermal};
		$inner_gpad_thermal_sym =~ s/\$\{OUT\}/$tmp_size/;
		$tmp_size = $COUPON_DATA->{pad_size};
		$inner_gpad_thermal_sym =~ s/\$\{IN\}/$tmp_size/;		   
		
		foreach my $layer_number (1 .. $COUPON_DATA->{layer_count}){
			my $tl_name;
			if ($layer_number == 1){
				$tl_name = 'top';
			}
			elsif($layer_number == $COUPON_DATA->{layer_count}){
				$tl_name = 'bottom';
			}
			else{
				$tl_name = 'l'.$layer_number;
			}
			my $layer_name = $gen_layer{$tl_name};
			my $layer_matrix = $matrix->{$layer_name};
			my $layer_polarity = $layer_matrix->{polarity};
			my $layer_polarity_n = ($layer_polarity eq 'positive')?'negative':'positive';
			#my $layer_side = ($layer_number <= $COUPON_DATA->{layer_count}/2)?'front':'back';
			my $layer_side ;
			if ($layer_number == 1) {
				$layer_side = 'front';
			}elsif( $layer_number ==  $COUPON_DATA->{layer_count}){
				$layer_side = 'back';
			}else{
				$layer_side = $layer_number%2 ? 'back':'front';
			}
			
			
			my ($layer_tpad_sym,$layer_gpad_sym,$layer_tpad_clear_sym,$layer_gpad_clear_sym,
				$layer_tdrl_clear_sym,$layer_gdrl_clear_sym,$layer_gpad_thermal_sym,$layer_patch_ref_clear_sym);
			if ($layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}){
				$layer_tpad_sym = $outer_tpad_sym; $layer_gpad_sym = $outer_gpad_sym;
				$layer_tpad_clear_sym =  $outer_tpad_clear_sym; $layer_gpad_clear_sym =  $outer_gpad_clear_sym; 
				$layer_tdrl_clear_sym =  $outer_tdrl_clear_sym; $layer_gdrl_clear_sym =  $outer_gdrl_clear_sym; 
				$layer_gpad_thermal_sym = $outer_gpad_thermal_sym;
				$layer_patch_ref_clear_sym = $outer_patch_ref_clear_sym;
			}
			else{
				$layer_tpad_sym = $inner_tpad_sym; $layer_gpad_sym = $inner_gpad_sym;
				$layer_tpad_clear_sym =  $inner_tpad_clear_sym; $layer_gpad_clear_sym =  $inner_gpad_clear_sym; 
				$layer_tdrl_clear_sym =  $inner_tdrl_clear_sym; $layer_gdrl_clear_sym =  $inner_gdrl_clear_sym; 
				$layer_gpad_thermal_sym = $inner_gpad_thermal_sym;
				$layer_patch_ref_clear_sym = $inner_patch_ref_clear_sym;
			}
			#layer type
			my $layer_type;
			foreach my $imp_layer (values %{$COUPON_DATA->{layers}}){
				if ($imp_layer->{layer_number} == $layer_number){
					$layer_type = $imp_layer->{layer_type};
					last;
				}
			}
			
			#层属于哪些group
			my @layer_blong_grps;
			foreach my $grp (keys %{$COUPON_DATA->{group}}){
				foreach my $lyr (@{$COUPON_DATA->{group}{$grp}{all_layer}}){
					if ($COUPON_DATA->{layers}{$lyr}{layer_number} == $layer_number){
						push @layer_blong_grps , $grp unless grep({$_ eq $grp} @layer_blong_grps);
					}
				}
			}
			#层包含的group
			my @layer_include_grps;
			foreach my $drill (values %{$COUPON_DATA->{drills}}){
				if ($drill->{drl_start_num} == $layer_number or $drill->{drl_end_num} == $layer_number){
					@layer_include_grps = @{$drill->{include_coupon_groups}} if $drill->{include_coupon_groups};
					last;
				}
			}
			$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
			
			#铺背景铜，
			if ($layer_polarity eq 'negative'){
				$GEN->srFill(layer=>$layer_name,step_margin_x=>-$COUPON_DATA->{neg_copper_margin}/1000,step_margin_y=>-$COUPON_DATA->{neg_copper_margin}/1000,polarity=>$layer_polarity_n);
			}
			$GEN->srFill(layer=>$layer_name,step_margin_x=>$COUPON_DATA->{rout2copper_spacing}/1000,step_margin_y=>$COUPON_DATA->{rout2copper_spacing}/1000,polarity=>$layer_polarity);
			
			#添加信号线隔离;
			if ($layer_type =~ /^(S|B)$/){
				my $grp = $layer_blong_grps[0];
				#为信号层和空层添加信号组隔离线
				foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
					my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
					my $sym = 'r'.($imp_layer->{cam_line_width}+$imp_layer->{imp_line2copper}*2-$imp_layer->{default_compensation});

					foreach my $m ('lines1','lines2'){
						if ($imp_layer->{$m} and @{$imp_layer->{$m}}){
							my ($xs,$ys) = ($imp_layer->{$m}[0]{x},$imp_layer->{$m}[0]{y});
							foreach my $n (1..scalar(@{$imp_layer->{$m}})-1){
								my $it = $imp_layer->{$m}[$n];
								if ($it->{direction}){
									$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>$sym,polarity=>$layer_polarity_n);
								}
								else{
									$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>$sym,polarity=>$layer_polarity_n);
								}
								($xs,$ys) = ($it->{x},$it->{y});
							}
						}
					}
					if ($imp_layer->{center_lines} and @{$imp_layer->{center_lines}}){
						my ($xs,$ys) = ($imp_layer->{center_lines}[0]{x},$imp_layer->{center_lines}[0]{y});
						foreach my $n (1..scalar(@{$imp_layer->{center_lines}})-1){
							my $it = $imp_layer->{center_lines}[$n];
							if ($it->{direction}){
								$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>'r'.$imp_layer->{cam_total_width},polarity=>$layer_polarity_n);
							}
							else{
								$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>'r'.$imp_layer->{cam_total_width},polarity=>$layer_polarity_n);
							}
							($xs,$ys) = ($it->{x},$it->{y});
						}
					}
					
					#aoi pad 隔离
					if ($COUPON_DATA->{add_aoi_pad} eq 'yes'){
						my $sym;
						if ($imp_layer->{impedance_type} =~ /coplanar/){
							$sym = 'r'.($imp_layer->{cam_line_width}+$COUPON_DATA->{aoi_pad_ar}*2+$imp_layer->{imp_line2copper}*2);
						}
						else{
							$sym = 'r'.($imp_layer->{cam_line_width}+$COUPON_DATA->{aoi_pad_ar}*2+$COUPON_DATA->{aoi_pad2copper}*2);
						}
						foreach my $it (@{$imp_layer->{aoi_pads}}){
							$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$sym,polarity=>$layer_polarity_n);
						}
					}
				}
			}
			#文字隔离
			if ($COUPON_DATA->{body_text_polarity} eq 'positive'){
				if ($COUPON_DATA->{body_text_pos}{$tl_name} and !$COUPON_DATA->{'body_text_not_enought_space'}{$tl_name}){
					my $n = 0;
					foreach my $text (@{$COUPON_DATA->{body_text_pos}{$tl_name}}){
						$n++;
						$GEN->addRectangle(x1=>$text->{xmin}-$COUPON_DATA->{body_text_free_x}/1000+$ShiftX,
										   y1=>$text->{ymin}-$COUPON_DATA->{body_text_free_y}/1000+$ShiftY,
										   x2=>$text->{xmax}+$COUPON_DATA->{body_text_free_x}/1000+$ShiftX,
										   y2=>$text->{ymax}+$COUPON_DATA->{body_text_free_y}/1000+$ShiftY,
										   attributes=>{attribute=>'.string',text=>'body_text_clear_'.$n},
										   polarity=>$layer_polarity_n,
									);
						if ($text->{angle}){
							my $angle = -$text->{angle};
							$angle = 360 + $angle if $angle < 0;
							$GEN->selClearFeature();
							$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>'body_text_clear_'.$n}]);
							$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',
								x_anchor=>$text->{bx}+$ShiftX,y_anchor=>$text->{by}+$ShiftY,
								angle=>$angle,x_scale=>1,y_scale=>1,x_offset=>0,y_offset=>0) if $GEN->getSelectCount();;
						}
					}
				}
			}
			
			#添加pin hole clearance
			my $pin_clear_symbol = 'r'.($COUPON_DATA->{pin_hole_size} + 2*$COUPON_DATA->{pin_hole_clearance});
			foreach my $lr ('left','right'){
				if ($COUPON_DATA->{$lr.'_pin_hole'}){
					$GEN->addPad(x=>$COUPON_DATA->{$lr.'_pin_hole'}{x}+$ShiftX,y=>$COUPON_DATA->{$lr.'_pin_hole'}{y}+$ShiftY,symbol=>$pin_clear_symbol,polarity=>$layer_polarity_n);
				}
			}
			
			#添加test pad隔离
			foreach my $grp (keys %{$COUPON_DATA->{group}}){
				my $tmp_tst_clear_sym;
				if (($layer_type eq 'S' and grep({$_ eq $grp} @layer_blong_grps)) or grep({$_ eq $grp} @layer_include_grps)){ #
					$tmp_tst_clear_sym = $layer_tpad_clear_sym;
				}
				else{
					$tmp_tst_clear_sym = $layer_tdrl_clear_sym;
				}
				foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
					my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
					foreach my $lr ('left','right'){
						if ($imp_layer->{$lr.'_tpads'}){
							foreach my $it (@{$imp_layer->{$lr.'_tpads'}}){
								$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_tst_clear_sym,polarity=>$layer_polarity_n,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
							}
						}
					}
				}
			}
			
			#添加gnd pad隔离
			if ($layer_type =~ /^(S|B)$/){
				if ($COUPON_DATA->{is_coplanar}){
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							
							my ($tmp_sym,$tmp_polarity);
							if (grep({$grp eq $_} @layer_blong_grps)){
								if ($imp_layer->{impedance_type} =~ /coplanar/i){
									$tmp_sym = $layer_gpad_sym;$tmp_polarity = $layer_polarity;
								}
								else{
									$tmp_sym = $layer_gpad_clear_sym; $tmp_polarity = $layer_polarity_n;
								}
							}
							elsif(grep({$grp eq $_} @layer_include_grps)){
								$tmp_sym = $layer_gpad_clear_sym; $tmp_polarity = $layer_polarity_n;
							}
							else{
								$tmp_sym = $layer_gdrl_clear_sym; $tmp_polarity = $layer_polarity_n;
							}
							
							foreach my $lr ('left','right') {
								if ($imp_layer->{$lr.'_gpads'}) {
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}) {
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
									}
								}
							}
						}
					}
				}
				else{
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						my ($tmp_sym,$tmp_polarity);
						if(grep({$grp eq $_} @layer_include_grps)){
							$tmp_sym = $layer_gpad_clear_sym; $tmp_polarity = $layer_polarity_n;
						}
						else{
							$tmp_sym = $layer_gdrl_clear_sym; $tmp_polarity = $layer_polarity_n;
						}
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_gpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
									}
								}
							}
						}
					}
					if ((($layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_copper_fill} !~ /outer/) or
						(($layer_number != 1 and $layer_number != $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_copper_fill} !~ /inner/))
					{
						foreach my $lr ('left','right'){
							$GEN->addRectangle(x1=>$COUPON_DATA->{$lr.'_header_copper_clip'}{xmin}+$ShiftX,y1=>$COUPON_DATA->{$lr.'_header_copper_clip'}{ymin}+$ShiftY,
										   x2=>$COUPON_DATA->{$lr.'_header_copper_clip'}{xmax}+$ShiftX,y2=>$COUPON_DATA->{$lr.'_header_copper_clip'}{ymax}+$ShiftY,
										   attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'},polarity=>$layer_polarity_n
										   ) if ($COUPON_DATA->{$lr.'_header_copper_clip'} and abs($COUPON_DATA->{$lr.'_header_copper_clip'}{xmax} - $COUPON_DATA->{$lr.'_header_copper_clip'}{xmin}) > 0.001);
						}
					}
					else{
						if ((($layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_clear_p2p_copper} =~ /outer/) or
							(($layer_number != 1 and $layer_number != $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_clear_p2p_copper} =~ /inner/))
						{
							#刮Pad中间的残铜
							my $tmp_resize;
							if ($layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}){
								$tmp_resize = $COUPON_DATA->{pad_size}/2000 + $COUPON_DATA->{outer_pad2copper}/1000;
							}
							else{
								$tmp_resize = $COUPON_DATA->{pad_size}/2000 + $COUPON_DATA->{inner_pad2copper}/1000;
							}
							
							foreach my $lr ('left','right'){
								my @tmp_x; my @tmp_y;
								foreach my $grp (keys %{$COUPON_DATA->{group}}){
									foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
										my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
										foreach my $tg ('tpads','gpads'){
											if ($imp_layer->{$lr.'_'.$tg}){
												foreach my $it (@{$imp_layer->{$lr.'_'.$tg}}){
													push @tmp_x, $it->{x} + $tmp_resize;
													push @tmp_x, $it->{x} - $tmp_resize;
													push @tmp_y, $it->{y} + $tmp_resize;
													push @tmp_y, $it->{y} - $tmp_resize;
												}
											}
										}
									}
								}
								@tmp_x = sort{$a <=> $b} @tmp_x;
								@tmp_y = sort{$a <=> $b} @tmp_y;
								my $min_x = $tmp_x[0];
								my $min_y = $tmp_y[0];
								my $max_x = $tmp_x[-1];
								my $max_y = $tmp_y[-1];
								if ($max_x - $min_x > 0.0001 and $max_y - $min_y > 0.0001){
									$GEN->addRectangle(x1=>$min_x+$ShiftX,y1=>$min_y+$ShiftY,
											x2=>$max_x+$ShiftX,y2=>$max_y+$ShiftY,
											attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'},polarity=>$layer_polarity_n
											); 
								}
							}
						}
					}
				}
			}
			elsif($layer_type eq 'R'){
	
				foreach my $grp (keys %{$COUPON_DATA->{group}}){
					my ($tmp_sym,$tmp_polarity);
					if (grep({$grp eq $_} @layer_blong_grps)){
						$tmp_sym = $layer_gpad_sym;$tmp_polarity = $layer_polarity;
					}
					elsif(grep({$grp eq $_} @layer_include_grps)){
						$tmp_sym = $layer_gpad_clear_sym; $tmp_polarity = $layer_polarity_n;
					}
					else{
						$tmp_sym = $layer_gdrl_clear_sym; $tmp_polarity = $layer_polarity_n;
					}
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						foreach my $lr ('left','right'){
							if ($imp_layer->{$lr.'_gpads'}){
								foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
									$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
								}
							}
						}
					}
				}
				
				
			}
			else{
				foreach my $grp (keys %{$COUPON_DATA->{group}}){
					my $tmp_gnd_clear_sym;
					if (grep({$_ eq $grp} @layer_include_grps)){ #
						$tmp_gnd_clear_sym = $layer_gpad_clear_sym;
					}
					else{
						$tmp_gnd_clear_sym = $layer_gdrl_clear_sym;
					}
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						foreach my $lr ('left','right'){
							if ($imp_layer->{$lr.'_gpads'}){
								foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
									$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_gnd_clear_sym,polarity=>$layer_polarity_n,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
								}
							}
						}
					}
				}
				if ((($layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_copper_fill} !~ /outer/) or
						(($layer_number != 1 and $layer_number != $COUPON_DATA->{layer_count}) and $COUPON_DATA->{header_copper_fill} !~ /inner/))
				{
					foreach my $lr ('left','right'){
						$GEN->addRectangle(x1=>$COUPON_DATA->{$lr.'_header_copper_clip'}{xmin}+$ShiftX,y1=>$COUPON_DATA->{$lr.'_header_copper_clip'}{ymin}+$ShiftY,
										   x2=>$COUPON_DATA->{$lr.'_header_copper_clip'}{xmax}+$ShiftX,y2=>$COUPON_DATA->{$lr.'_header_copper_clip'}{ymax}+$ShiftY,
										   attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'},polarity=>$layer_polarity_n
										   ) if ($COUPON_DATA->{$lr.'_header_copper_clip'} and abs($COUPON_DATA->{$lr.'_header_copper_clip'}{xmax} - $COUPON_DATA->{$lr.'_header_copper_clip'}{xmin}) > 0.001);
						}
				}
				
			}
			
			
			if ($COUPON_DATA->{thermal_as_surface} eq 'yes'){
				#添加gnd thermal
				if ($layer_type =~ /^(S|B)$/ and $COUPON_DATA->{is_coplanar}){
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						my ($tmp_sym,$tmp_polarity);
						if (grep({$grp eq $_} @layer_blong_grps)){
							$tmp_sym = $layer_gpad_thermal_sym;$tmp_polarity = $layer_polarity_n;
						}
						next unless $tmp_sym;
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_gpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
									}
								}
							}
						}
					}
				}
				elsif($layer_type eq 'R'){
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						my ($tmp_sym,$tmp_polarity);
						if (grep({$grp eq $_} @layer_blong_grps)){
							$tmp_sym = $layer_gpad_thermal_sym;$tmp_polarity = $layer_polarity_n;
						}
						next unless $tmp_sym;
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_gpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_clear_pad'});
									}
								}
							}
						}
					}
				}
				
				if ($COUPON_DATA->{patch_ref_layer_hole} and $layer_type eq 'R'){
					$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
					$GEN->createLayer(job=>$Job,layer=>$tmp_layer,context=>'misc',type=>'signal');
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_layer,clear_before=>'yes');
					foreach my $grp (@layer_blong_grps){
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							my $sym = 'r'.($imp_layer->{cam_line_width} + $COUPON_DATA->{patch_ref_layer_hole}*2);
							foreach my $m ('lines1','lines2'){
								if ($imp_layer->{$m} and @{$imp_layer->{$m}}){
									my ($xs,$ys) = ($imp_layer->{$m}[0]{x},$imp_layer->{$m}[0]{y});
									foreach my $n (1..scalar(@{$imp_layer->{$m}})-1){
										my $it = $imp_layer->{$m}[$n];
										if ($it->{direction}){
											$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>$sym,polarity=>'positive');
										}
										else{
											$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>$sym,polarity=>'positive');
										}
										($xs,$ys) = ($it->{x},$it->{y});
									}
								}
								
							}
							if ($imp_layer->{center_lines} and @{$imp_layer->{center_lines}}){
								my ($xs,$ys) = ($imp_layer->{center_lines}[0]{x},$imp_layer->{center_lines}[0]{y});
								foreach my $n (1..scalar(@{$imp_layer->{center_lines}})-1){
									my $it = $imp_layer->{center_lines}[$n];
									if ($it->{direction}){
										$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>'r'.$imp_layer->{cam_total_width},polarity=>$layer_polarity_n);
									}
									else{
										$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>'r'.$imp_layer->{cam_total_width},polarity=>'positive');
									}
									($xs,$ys) = ($it->{x},$it->{y});
								}
							}
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_tpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_tpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$layer_patch_ref_clear_sym,polarity=>'negative',attributes=>{attribute=>'.string',text=>$lr.'_patch_ref_clear_pad'});
									}
								}
							}
							foreach my $lr ('left','right'){
								if ($trans->{$lr}{angle}){
									$GEN->selClearFeature();
									$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_patch_ref_clear_pad'}]);
									$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
								}
							}
							
							
							$GEN->COM('sel_all_feat');
							$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
							$GEN->COM('sel_all_feat');
							$GEN->COM('sel_move_other',target_layer=>$layer_name,invert=>($layer_polarity eq 'positive')?'no':'yes',dx=>0,dy=>0,size=>0);
									
						}
					}
					
					
					
					$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
					foreach my $lr ('left','right'){
						if ($trans->{$lr}{angle}){
							$GEN->selClearFeature();
							$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_clear_pad'}]);
							$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
						}
					}
					$GEN->COM('sel_all_feat');
					$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>$COUPON_DATA->{inner_pad2copper} - 1,clean_hole_mode=>'x_or_y');
				}
				
			}
			
			foreach my $lr ('left','right'){
				if ($trans->{$lr}{angle}){
					$GEN->selClearFeature();
					$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_clear_pad'}]);
					$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
				}
			}
			$GEN->COM('sel_all_feat');
			$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
			
			if ($layer_polarity eq 'negative'){
				$GEN->clipArea(area=>'profile',area_type=>'rectangle',inout=>'outside',contour_cut=>'yes',margin=>$COUPON_DATA->{neg_copper_margin});
			}
			else{
				$GEN->COM('sel_all_feat');
				$GEN->selFill(type=>'solid',solid_type=>'fill',min_brush=>$COUPON_DATA->{copper_fill_line_width});
				$GEN->COM('sel_all_feat');
				$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
				$GEN->createLayer(job=>$Job,layer=>$tmp_layer,context=>'misc',type=>'signal') unless ($GEN->isLayerExists(job=>$Job,layer=>$tmp_layer));;
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_layer,clear_before=>'yes');
				$GEN->COM('sel_all_feat');
				$GEN->selDelete();
				$GEN->srFill(layer=>$tmp_layer,step_margin_x=>$COUPON_DATA->{rout2copper_spacing}/1000-0.1,step_margin_y=>$COUPON_DATA->{rout2copper_spacing}/1000-0.1,polarity=>$layer_polarity);
				$GEN->copyLayer(source_job=>$Job,source_step=>$step,source_layer=>$layer_name,dest_layer=>$tmp_layer,mode=>'append',invert=>'yes');
				$GEN->COM('sel_all_feat');
				$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
				$GEN->COM('sel_all_feat');
				$GEN->selFill(type=>'solid',solid_type=>'fill',min_brush=>$COUPON_DATA->{copper_fill_sliver_width});
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
				$GEN->COM('sel_all_feat');
				$GEN->selDelete();
				$GEN->srFill(layer=>$layer_name,step_margin_x=>$COUPON_DATA->{rout2copper_spacing}/1000,step_margin_y=>$COUPON_DATA->{rout2copper_spacing}/1000,polarity=>$layer_polarity);
				$GEN->copyLayer(source_job=>$Job,source_step=>$step,source_layer=>$tmp_layer,dest_layer=>$layer_name,mode=>'append',invert=>'yes');
				$GEN->COM('sel_all_feat');
				$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
				if ($COUPON_DATA->{clean_surface_size}){
					$GEN->runSingleDfm(chklist=>'valor_dfm_clean_holes',
									   params=>{pp_layer => $layer_name,
												pp_size=>$COUPON_DATA->{clean_surface_size},
												pp_mode=>'X and Y',
												pp_hi=>'Cover islands',
												pp_cover_f=>'Surfaces',},
									   area => 'global',show => 'no',show_res=>'no');
					$GEN->COM('sel_all_feat');
					$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
					$GEN->deleteLayer(job=>$Job,layer=>$layer_name.'+++');
				}
				
			}
			$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
			#添加test pad
			foreach my $grp (keys %{$COUPON_DATA->{group}}){
				if ($COUPON_DATA->{remove_nfp} ne 'yes' or
					(grep({$grp eq $_} @layer_blong_grps) and $layer_type eq 'S' ) or
					grep({$grp eq $_} @layer_include_grps ))
				{
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						if ($COUPON_DATA->{remove_nfp} ne 'yes' or $imp_layer->{layer_number} == $layer_number
							or $layer_number == 1 or $layer_number == $COUPON_DATA->{layer_count}){
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_tpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_tpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$layer_tpad_sym,polarity=>$layer_polarity,attributes=>{attribute=>'.string',text=>$lr.'_pad'});
									}
								}
							}
						}
					}
				}
			}
			
			#添加gnd pad
			if ($layer_type =~ /^(S|B)$/){
				if ($COUPON_DATA->{is_coplanar}){
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							my ($tmp_sym,$tmp_polarity);
							
							if (grep({$grp eq $_} @layer_blong_grps)){
								if ($imp_layer->{impedance_type} =~ /coplanar/i){
									unless ($COUPON_DATA->{thermal_as_surface} eq 'yes'){
										$tmp_sym = $layer_gpad_thermal_sym;$tmp_polarity = $layer_polarity_n;
									}
								}
								else{
									$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
								}
							}
							elsif(grep({$grp eq $_} @layer_include_grps)){
								$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
							}
							elsif($COUPON_DATA->{remove_nfp} ne 'yes'){
								$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
							}
							next unless $tmp_sym;
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_gpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_pad'});
									}
								}
							}
							
						}
						
					}
				}
				else{
					foreach my $grp (keys %{$COUPON_DATA->{group}}){
						my ($tmp_sym,$tmp_polarity);
						if(grep({$grp eq $_} @layer_include_grps)){
							$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
						}
						elsif($COUPON_DATA->{remove_nfp} ne 'yes'){
							$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
						}
						next unless $tmp_sym;
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							foreach my $lr ('left','right'){
								if ($imp_layer->{$lr.'_gpads'}){
									foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_pad'});
									}
								}
							}
						}
					}
				}
			}
			elsif($layer_type eq 'R'){
				foreach my $grp (keys %{$COUPON_DATA->{group}}){
					my ($tmp_sym,$tmp_polarity);
					if (grep({$grp eq $_} @layer_blong_grps)){
						unless ($COUPON_DATA->{thermal_as_surface} eq 'yes'){
							$tmp_sym = $layer_gpad_thermal_sym;$tmp_polarity = $layer_polarity_n;
						}
					}
					elsif(grep({$grp eq $_} @layer_include_grps)){
						$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
					}
					elsif($COUPON_DATA->{remove_nfp} ne 'yes'){
						$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
					}
					next unless $tmp_sym;
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						foreach my $lr ('left','right'){
							if ($imp_layer->{$lr.'_gpads'}){
								foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
									$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_pad'});
								}
							}
						}
					}
				}
			}
			else{
				foreach my $grp (keys %{$COUPON_DATA->{group}}){
					my ($tmp_sym,$tmp_polarity);
					if(grep({$grp eq $_} @layer_include_grps)){
						$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
					}
					elsif($COUPON_DATA->{remove_nfp} ne 'yes'){
						$tmp_sym = $layer_gpad_sym; $tmp_polarity = $layer_polarity;
					}
					next unless $tmp_sym;
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						foreach my $lr ('left','right'){
							if ($imp_layer->{$lr.'_gpads'}){
								foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
									$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tmp_sym,polarity=>$tmp_polarity,attributes=>{attribute=>'.string',text=>$lr.'_pad'});
								}
							}
						}
					}
				}
			}
			
			if ($COUPON_DATA->{patch_ref_layer_hole}  and $COUPON_DATA->{thermal_as_surface} ne 'yes' and $layer_type eq 'R'){
				$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
				$GEN->createLayer(job=>$Job,layer=>$tmp_layer,context=>'misc',type=>'signal');
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_layer,clear_before=>'yes');
				foreach my $grp (@layer_blong_grps){
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						my $sym = 'r'.($imp_layer->{cam_line_width} + $COUPON_DATA->{patch_ref_layer_hole}*2);
						foreach my $m ('lines1','lines2'){
							if ($imp_layer->{$m} and @{$imp_layer->{$m}}){
								my ($xs,$ys) = ($imp_layer->{$m}[0]{x},$imp_layer->{$m}[0]{y});
								foreach my $n (1..scalar(@{$imp_layer->{$m}})-1){
									my $it = $imp_layer->{$m}[$n];
									if ($it->{direction}){
										$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>$sym,polarity=>'positive');
									}
									else{
										$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>$sym,polarity=>'positive');
									}
									($xs,$ys) = ($it->{x},$it->{y});
								}
							}
						}
						foreach my $lr ('left','right'){
							if ($imp_layer->{$lr.'_tpads'}){
								foreach my $it (@{$imp_layer->{$lr.'_tpads'}}){
									$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$layer_patch_ref_clear_sym,polarity=>'negative',attributes=>{attribute=>'.string',text=>$lr.'_patch_ref_clear_pad'});
								}
							}
						}
						foreach my $lr ('left','right'){
							if ($trans->{$lr}{angle}){
								$GEN->selClearFeature();
								$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_patch_ref_clear_pad'}]);
								$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
							}
						}
						$GEN->COM('sel_all_feat');
						$GEN->selContourize(accuracy=>0.1,break_to_islands=>'yes',clean_hole_size=>0.1,clean_hole_mode=>'x_or_y');
						$GEN->COM('sel_all_feat');
						$GEN->COM('sel_move_other',target_layer=>$layer_name,invert=>($layer_polarity eq 'positive')?'no':'yes',dx=>0,dy=>0,size=>0);
								
						
					}
				}
				$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
			}
			
			
			
			#添加信号线及AOI Pad
			foreach my $imp_layer (values %{$COUPON_DATA->{layers}}){
				if ($imp_layer->{layer_number} == $layer_number){
					my $sym = 'r'.($imp_layer->{cam_line_width});
					foreach my $m ('lines1','lines2'){
						if ($imp_layer->{$m} and @{$imp_layer->{$m}}){
							my ($xs,$ys) = ($imp_layer->{$m}[0]{x},$imp_layer->{$m}[0]{y});
							foreach my $n (1..scalar(@{$imp_layer->{$m}})-1){
								my $it = $imp_layer->{$m}[$n];
								if ($it->{direction}){
									$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>$sym,polarity=>$layer_polarity);
								}
								else{
									$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>$sym,polarity=>$layer_polarity);
								}
								($xs,$ys) = ($it->{x},$it->{y});
							}
						}
					}
					if ($COUPON_DATA->{add_aoi_pad} eq 'yes'){
						foreach my $it (@{$imp_layer->{aoi_pads}}){
							$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>'r'.($imp_layer->{cam_line_width}+$COUPON_DATA->{aoi_pad_ar}*2),polarity=>$layer_polarity);
						}
					}
					
				}
			}
			
			#添加头部文字
			foreach my $lr ('left','right'){
				if ($COUPON_DATA->{$lr.'_header_text_pos'}{$tl_name}){
					foreach my $sig (keys %{$COUPON_DATA->{$lr.'_header_text_pos'}{$tl_name}}){
						foreach my $v (values %{$COUPON_DATA->{$lr.'_header_text_pos'}{$tl_name}{$sig}}){
							my $tmp_polarity = ($v->{polarity} eq 'positive')?$layer_polarity:$layer_polarity_n;
							$GEN->addText(x=>$v->{x}+$ShiftX,y=>$v->{y}+$ShiftY,text=>$v->{text},angle=>$v->{angle},mirror=>($layer_side eq 'front')?'no':'yes',
										  x_size=>$v->{x_size},y_size=>$v->{y_size},line_width=>$v->{line_width},anchor=>$v->{anchor},
										  polarity=>$tmp_polarity,fontname=>$COUPON_DATA->{header_text_font},
										  attributes=>{attribute=>'.string',text=>$lr.'_pad'});
						}
					}
				}
				
			}
			
			foreach my $lr ('left','right'){
				if ($trans->{$lr}{angle}){
					$GEN->selClearFeature();
					$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_pad'}]);
					$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();
				}
			}
			
			#$GUI->debug(-text=>dump($COUPON_DATA->{body_text_pos},$tl_name));
			
			#添加body文字

			if ($tl_name eq 'top' and $COUPON_DATA->{body_text_pos}{$tl_name}){
				unless ($COUPON_DATA->{'body_text_not_enought_space'}{$tl_name}){
					my $n = 0;
					foreach my $text (@{$COUPON_DATA->{body_text_pos}{$tl_name}}){
						$n++;
						$GEN->addText(x=>$text->{x}+$ShiftX,y=>$text->{y}+$ShiftY,text=>$text->{text},angle=>0,polarity=>($COUPON_DATA->{body_text_polarity} eq 'positive')?$layer_polarity:$layer_polarity_n,
									  x_size=>$text->{x_size},y_size=>$text->{y_size},line_width=>$text->{line_width},mirror=>($layer_side eq 'front')?'no':'yes',
									  anchor=>$text->{anchor},text_length=>$text->{text_length},attributes=>{attribute=>'.string',text=>'body_text_'.$n},fontname=>$COUPON_DATA->{body_text_font},);
						if ($text->{angle}){
							my $angle = -$text->{angle};
							$angle = 360 + $angle if $angle < 0;
							$GEN->selClearFeature();
							$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>'body_text_'.$n}]);
							$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',
								x_anchor=>$text->{bx}+$ShiftX,y_anchor=>$text->{by}+$ShiftY,
								angle=>$angle,x_scale=>1,y_scale=>1,x_offset=>0,y_offset=>0) if $GEN->getSelectCount();;
						}
					}
				}
				else{
					my $tmp_body_text_layer = $layer_name.($COUPON_DATA->{body_text_tmp_layer_postfix} || '_imptext+++');
					push @$WarningMsg,"${step}的${layer_name}层没有足够的空间添加文字,现将文字添加到${tmp_body_text_layer}中!";
					$GEN->createLayer(job=>$Job,layer=>$tmp_body_text_layer,context=>'misc',type=>'signal') unless ($GEN->isLayerExists(job=>$Job,layer=>$tmp_body_text_layer));;
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_body_text_layer,clear_before=>'yes');
					$GEN->COM('sel_all_feat');
					$GEN->selDelete();
					foreach my $text (@{$COUPON_DATA->{body_text_pos}{$tl_name}}){
						$GEN->addText(x=>$text->{x},y=>$text->{y},text=>$text->{text},angle=>0,polarity=>$layer_polarity,
									  x_size=>$text->{x_size},y_size=>$text->{y_size},line_width=>$text->{line_width},mirror=>($layer_side eq 'front')?'no':'yes',
									  anchor=>$text->{anchor},fontname=>$COUPON_DATA->{body_text_font},);
					}
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
				}
			}

=exp
			foreach my $layer (keys %{$COUPON_DATA->{body_text_pos}}) {
				unless ($COUPON_DATA->{'body_text_not_enought_space'}{$layer}){
					my $n = 0;
					foreach my $text (@{$COUPON_DATA->{body_text_pos}{$layer}}){
						my ($txt_lyr) = $text->{text} =~ /(\w+)\//i;
$GEN->PAUSE($text->{text}.' -- '.$txt_lyr.' --- '.$tl_name);
						if (lc($txt_lyr) eq  $tl_name or $text->{text} =~ /\$\$JOB/) {
							$n++;
							$GEN->addText(x=>$text->{x}+$ShiftX,y=>$text->{y}+$ShiftY,text=>$text->{text},angle=>0,polarity=>($COUPON_DATA->{body_text_polarity} eq 'positive')?$layer_polarity:$layer_polarity_n,
										  x_size=>$text->{x_size},y_size=>$text->{y_size},line_width=>$text->{line_width},mirror=>($layer_side eq 'front')?'no':'yes',
										  anchor=>$text->{anchor},text_length=>$text->{text_length},attributes=>{attribute=>'.string',text=>'body_text_'.$n},fontname=>$COUPON_DATA->{body_text_font},);
							if ($text->{angle}){
								my $angle = -$text->{angle};
								$angle = 360 + $angle if $angle < 0;
								$GEN->selClearFeature();
								$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>'body_text_'.$n}]);
								$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',
									x_anchor=>$text->{bx}+$ShiftX,y_anchor=>$text->{by}+$ShiftY,
									angle=>$angle,x_scale=>1,y_scale=>1,x_offset=>0,y_offset=>0) if $GEN->getSelectCount();;
							}
						}
					}
				}else{
					my $tmp_body_text_layer = $layer_name.($COUPON_DATA->{body_text_tmp_layer_postfix} || '_imptext+++');
					push @$WarningMsg,"${step}的${layer_name}层没有足够的空间添加文字,现将文字添加到${tmp_body_text_layer}中!";
					$GEN->createLayer(job=>$Job,layer=>$tmp_body_text_layer,context=>'misc',type=>'signal') unless ($GEN->isLayerExists(job=>$Job,layer=>$tmp_body_text_layer));;
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$tmp_body_text_layer,clear_before=>'yes');
					$GEN->COM('sel_all_feat');
					$GEN->selDelete();
					foreach my $text (@{$COUPON_DATA->{body_text_pos}{$layer}}){
						$GEN->addText(x=>$text->{x},y=>$text->{y},text=>$text->{text},angle=>0,polarity=>$layer_polarity,
									  x_size=>$text->{x_size},y_size=>$text->{y_size},line_width=>$text->{line_width},mirror=>($layer_side eq 'front')?'no':'yes',
									  anchor=>$text->{anchor},fontname=>$COUPON_DATA->{body_text_font},);
					}
					$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$layer_name,clear_before=>'yes');
				}
			}
=cut
		}	
		if ($COUPON_DATA->{header_not_enought_space}){
			#push @$WarningMsg,"${step}中没有足够的空间添加头部文字,请检查并处理!";
		}
		
		#添加钻孔
		foreach my $drl (keys %{$COUPON_DATA->{drills}}){
			my $drl_layer = $gen_layer{$drl};
			$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$drl_layer,clear_before=>'yes');
			my $hole_sym = 'r'.(($drl eq 'drill')?$COUPON_DATA->{hole_size}:$COUPON_DATA->{hdi_hole_size});
			if ($COUPON_DATA->{drills}{$drl}{include_coupon_groups}){
				foreach my $grp (@{$COUPON_DATA->{drills}{$drl}{include_coupon_groups}}){
					foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
						my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
						foreach my $lr ('left','right'){
							foreach my $pad ('_tpads','_gpads'){
								if ($imp_layer->{$lr.$pad}){
									foreach my $it (@{$imp_layer->{$lr.$pad}}){
										$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$hole_sym,polarity=>'positive',attributes=>[{attribute=>'.string',text=>$lr.'_hole'},{attribute=>'.drill',option=>'plated'}]);
									}
								}
							}
						}
					}
				}
			}
			foreach my $lr ('left','right'){
				if ($trans->{$lr}{angle}){
					$GEN->selClearFeature();
					$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_hole'}]);
					$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
				}
			}
			
			if ($drl eq 'drill'){
				#pin_hole
				foreach my $lr ('left','right'){
					if ($COUPON_DATA->{$lr.'_pin_hole'}){
						$GEN->addPad(x=>$COUPON_DATA->{$lr.'_pin_hole'}{x}+$ShiftX,y=>$COUPON_DATA->{$lr.'_pin_hole'}{y}+$ShiftY,symbol=>'r'.$COUPON_DATA->{pin_hole_size},polarity=>'positive',attributes=>[{attribute=>'.drill',option=>'non_plated'}]);
					}
				}
				#coplanar hole
				foreach my $ud ('up','down'){
					if ($COUPON_DATA->{$ud.'_coplanar_holes'}){
						foreach my $it (@{$COUPON_DATA->{$ud.'_coplanar_holes'}}){
							$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>'r'.$COUPON_DATA->{coplanar_hole_size},attributes=>[{attribute=>'.drill',option=>'plated'}]);
						}
					}
				}
			}
		}
		
		#npth
		if ($COUPON_DATA->{add_pin_hole} eq 'yes' and $gen_layer{npth}){
			$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$gen_layer{npth},clear_before=>'yes');
			foreach my $lr ('left','right'){
				if ($COUPON_DATA->{$lr.'_pin_hole'}){
					$GEN->addPad(x=>$COUPON_DATA->{$lr.'_pin_hole'}{x}+$ShiftX,y=>$COUPON_DATA->{$lr.'_pin_hole'}{y}+$ShiftY,symbol=>'r'.$COUPON_DATA->{pin_hole_size},polarity=>'positive',attributes=>[{attribute=>'.drill',option=>'non_plated'}]);
				}
			}
		}
		
		#防焊
		foreach my $item ('sm_fr','sm_ba'){
		#foreach my $item ('smt','smb'){
			my $tpad_sm_sym = $COUPON_DATA->{outer_tpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{sm_opening_ar}*2);
			my $gpad_sm_sym = $COUPON_DATA->{outer_gpad_shape} . ($COUPON_DATA->{pad_size} + $COUPON_DATA->{sm_opening_ar}*2);
			if ($gen_layer{$item}){
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$gen_layer{$item},clear_before=>'yes');
				foreach my $imp_layer (values %{$COUPON_DATA->{layers}}){
					next unless $imp_layer->{layer_type} eq 'S';
					foreach my $lr ('left','right'){
						if ($imp_layer->{$lr.'_tpads'}){
							foreach my $it (@{$imp_layer->{$lr.'_tpads'}}){
								$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$tpad_sm_sym,polarity=>'positive',attributes=>[{attribute=>'.string',text=>$lr.'_sm'}]);
							}
						}
						if ($imp_layer->{$lr.'_gpads'}){
							foreach my $it (@{$imp_layer->{$lr.'_gpads'}}){
								$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$gpad_sm_sym,polarity=>'positive',attributes=>[{attribute=>'.string',text=>$lr.'_sm'}]);
							}
						}
					}
				}
				foreach my $lr ('left','right'){
					if ($trans->{$lr}{angle}){
						$GEN->selClearFeature();
						$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_sm'}]);
						$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
					}
				}
				#添加pin hole sm
				foreach my $lr ('left','right'){
					if ($COUPON_DATA->{$lr.'_pin_hole'}){
						$GEN->addPad(x=>$COUPON_DATA->{$lr.'_pin_hole'}{x}+$ShiftX,y=>$COUPON_DATA->{$lr.'_pin_hole'}{y}+$ShiftY,symbol=>'r'.($COUPON_DATA->{pin_hole_size} + 2*$COUPON_DATA->{pin_hole_sm_ar}),polarity=>'positive',);
					}
				}
				
				#添加信号线SM开窗
				foreach my $imp_layer (values %{$COUPON_DATA->{layers}}){
					if (($imp_layer->{layer_number} == 1 and $item eq 'sm_fr' and lc($imp_layer->{sm_open}) eq 'yes') or
						($imp_layer->{layer_number} == $LayerCount and $item eq 'sm_ba' and lc($imp_layer->{sm_open}) eq 'yes') 
					){
						my $sym_size = ($imp_layer->{cam_line_width} + ($COUPON_DATA->{line_sm_opening_ar} || $COUPON_DATA->{sm_opening_ar})*2);
						foreach my $m ('lines1','lines2'){
							if ($imp_layer->{$m} and @{$imp_layer->{$m}}){
								my ($xs,$ys) = ($imp_layer->{$m}[0]{x},$imp_layer->{$m}[0]{y});
								foreach my $n (1..scalar(@{$imp_layer->{$m}})-1){
									my $it = $imp_layer->{$m}[$n];
									if ($it->{direction}){
										$GEN->addArc(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,xc=>$it->{xc}+$ShiftX,yc=>$it->{yc}+$ShiftY,direction=>$it->{direction},symbol=>'r'.$sym_size,polarity=>'positive');
									}
									else{
										$GEN->addLine(xs=>$xs+$ShiftX,ys=>$ys+$ShiftY,xe=>$it->{x}+$ShiftX,ye=>$it->{y}+$ShiftY,symbol=>'r'.$sym_size,polarity=>'positive');
									}
									($xs,$ys) = ($it->{x},$it->{y});
								}
							}
						}
						if ($COUPON_DATA->{add_aoi_pad} eq 'yes'){
							foreach my $it (@{$imp_layer->{aoi_pads}}){
								$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>'r'.($sym_size+$COUPON_DATA->{aoi_pad_ar}*2),polarity=>'positive');
							}
						}
					}
				}
			}
		}
		
		#outline
		if ($gen_layer{'outline'}){
			$GEN->COM('profile_to_rout',layer=>$gen_layer{'outline'},width=>$COUPON_DATA->{outline_width}||1);
		}
		
		#档点
		if ($COUPON_DATA->{plug_layers}){
			# 层名做变量替换
			$COUPON_DATA->{plug_layers} =~ s/\$\{layer_count\}/sprintf("%02d", $COUPON_DATA->{layer_count})/ge;
			my $layers = eval($COUPON_DATA->{plug_layers});
			while ($layers and @$layers){
				my $plug_layer = shift @$layers;
				my $action = shift @$layers;
				if ($action eq 'create'){
					if (!$GEN->isLayerExists(job=>$Job,layer=>$plug_layer)){
						$GEN->createLayer(job=>$Job,layer=>$plug_layer);
					}
				}
				next unless $GEN->isLayerExists(job=>$Job,layer=>$plug_layer);
				$GEN->affectedLayer(affected=>'yes',mode=>'single',layer=>$plug_layer,clear_before=>'yes');
				$GEN->COM('sel_all_feat');
				$GEN->selDelete;
				##挡点需要填充
				#$GEN->srFill(step_margin_x=>-0.005,step_margin_y=>-0.005);
				my $drl_layer = $gen_layer{drill};
				my $via_sym = 'r'.($COUPON_DATA->{hole_size} + 2*$COUPON_DATA->{plug_ar});
				if ($COUPON_DATA->{drills}{drill}{include_coupon_groups}){
					foreach my $grp (@{$COUPON_DATA->{drills}{drill}{include_coupon_groups}}){
						foreach my $imp_lyr (@{$COUPON_DATA->{group}{$grp}{signal_layer}}){
							my $imp_layer = $COUPON_DATA->{layers}{$imp_lyr};
							foreach my $lr ('left','right'){
								foreach my $pad ('_tpads','_gpads'){
									if ($imp_layer->{$lr.$pad}){
										foreach my $it (@{$imp_layer->{$lr.$pad}}){
											$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>$via_sym,polarity=>'positive',attributes=>[{attribute=>'.string',text=>$lr.'_hole'},{attribute=>'.drill',option=>'plated'}]);
										}
									}
								}
							}
						}
					}
				}
				foreach my $lr ('left','right'){
					if ($trans->{$lr}{angle}){
						$GEN->selClearFeature();
						$GEN->selectByFilter(attribute=>[{attribute=>'.string',text=>$lr.'_hole'}]);
						$GEN->COM('sel_transform',mode=>'anchor',oper=>'rotate',duplicate=>'no',%{$trans->{$lr}}) if $GEN->getSelectCount();;
					}
				}
				
				
				#pin_hole
				foreach my $lr ('left','right'){
					if ($COUPON_DATA->{$lr.'_pin_hole'}){
						$GEN->addPad(x=>$COUPON_DATA->{$lr.'_pin_hole'}{x}+$ShiftX,y=>$COUPON_DATA->{$lr.'_pin_hole'}{y}+$ShiftY,symbol=>'r'.($COUPON_DATA->{pin_hole_size} + 2*$COUPON_DATA->{plug_ar}),polarity=>'positive',attributes=>[{attribute=>'.drill',option=>'non_plated'}]);
					}
				}
				#coplanar hole
				foreach my $ud ('up','down'){
					if ($COUPON_DATA->{$ud.'_coplanar_holes'}){
						foreach my $it (@{$COUPON_DATA->{$ud.'_coplanar_holes'}}){
							$GEN->addPad(x=>$it->{x}+$ShiftX,y=>$it->{y}+$ShiftY,symbol=>'r'.($COUPON_DATA->{coplanar_hole_size} + 2*$COUPON_DATA->{plug_ar}),attributes=>[{attribute=>'.drill',option=>'plated'}]);
						}
					}
				}
			}
		}
		$GEN->deleteLayer(job=>$Job,layer=>$tmp_layer);
		$GEN->affectedLayer(mode=>'all',affected=>'yes');
		$GEN->COM('sel_all_feat');
		$GEN->COM('sel_delete_atr',attributes=>'.string');
		
		$GEN->COM('disp_on');
		$GEN->affectedLayer(mode=>'all',affected=>'no');
		if ($COUPON_DATA->{hooks_draw_post}){
			eval($COUPON_DATA->{hooks_draw_post});
		}
		##阻抗线补偿 Tomy 2017.12.14 阻抗在系统内部有做补偿脚本中不需要再补偿
		###$GEN->COM('disp_off');
		###foreach my $layer (sort {$matrix->{$a}{row} <=> $matrix->{$b}{row}}  keys %$matrix) {
		###	if($matrix->{$layer}{tl_type} =~ /(inner|outer)/ ){
		###		my $value = 0;
		###		if($matrix->{$layer}{tl_type} =~ /(inner)/ ){
		###			$value = $IKM->get_jobinfo(-jobid=>$JOB_ID,-jobcategory=>'work',-jobinfo=>'line_compensation_inner');
		###		}
		###		else{
		###			$value = $IKM->get_jobinfo(-jobid=>$JOB_ID,-jobcategory=>'work',-jobinfo=>'line_compensation_outer');
		###		}
		###		next unless $value;
		###		$GEN->affectedLayer(affected=>'yes',layer=>[$layer],clear_before=>'yes');
		###		$GEN->selectByFilter(feat_types=>'line\;arc',polarity=>'positive',profile=>'all');
		###		$GEN->selAddAttr(attribute=>[{attribute=>'tl_string',text=>'compensation_'.$value.'_mil'}])if ( $GEN->getSelectCount() > 0 );
		###		$GEN->selectByFilter(attribute=>[{attribute=>'tl_string',text=>'compensation_'.$value.'_mil'}]);
		###		$GEN->COM('sel_resize',size=>$value,corner_ctl=>'no')if ( $GEN->getSelectCount() > 0 );
		###	}
		###}
		###$GEN->COM('disp_on');
		
		$GEN->clearLayers();
		$GEN->affectedLayer(mode=>'all',affected=>'no');
		$GEN->closeStep();
	}
	if ($WarningMsg){
		$GUI->msgbox(-icon=>'warning',-text=>join("\n",@$WarningMsg));
		#$GEN->PAUSE('Please Edit Then Continue');
		my $html = '<html><body bgcolor="#EEEEFF" link="#0000FF" vlink="#FF00FF" alink="#FF0000" text="#000000"><FONT color="#FF00FF">';
		foreach my $item (@$WarningMsg){
			$html .= $item.'<p>';
		}
		$html .='</FONT></body></html>';
		
		$IKM->update_flow_report(-report=>$html,-job_id=>$ARGS{job_id},-process_id=>$ARGS{process_id});
		
		$Return = 'Warning';
	}
	else{
		$IKM->update_flow_report(-report=>'',-job_id=>$ARGS{job_id},-process_id=>$ARGS{process_id});
	}
	
	unless ($GEN->{STATUS}){
		return $Return;
	}
	else{
		$GUI->msgbox(-icon=>'error',-image=>'genesis_error',-compound=>'top',-text=>join("\n",@{$GEN->{STATUS}}));
		#addFlowNotes(-notes=>"   Genesis Error:\n   ".join("\n   ",@{$GEN->{STATUS}}));
		return 'Error';
	}	

}
catch Error::Simple with {
	my $error = encode("utf8",shift);
	print $error,"\n";
	$GUI->msgbox(-text=>$error);
	return 'Error';
}
finally{
	#$GEN->deleteLayer(layer=>$tmp_layer) if ($GEN->isLayerExists(job=>$job,layer=>$tmp_layer));
};


sub opt_lines{
	my @lines = @_;
	my %lines_hash;
	my $n = 0;
	my @return = (shift @lines);
	foreach my $line (@lines){
		$lines_hash{$n++} = $line;
	}
	
	#向前查找
	my ($xs,$ys) = ($return[0]{xs},$return[0]{ys});
	my ($xe,$ye) = ($return[0]{xe},$return[0]{ye});
	my $last_count = 0;
	while($last_count != scalar(keys %lines_hash)){
		$last_count = scalar(keys %lines_hash);
		foreach my $n (keys %lines_hash){
			my $line = $lines_hash{$n};
			if (abs($xs - $line->{xs}) < 0.0001 && abs($ys - $line->{ys}) < 0.0001){
				($line->{xs},$line->{ys},$line->{xe},$line->{ye}) =
				($line->{xe},$line->{ye},$line->{xs},$line->{ys});
				$line->{direction} = ($line->{direction} eq 'cw') ? 'ccw' : 'cw';
				($xs,$ys) = ($line->{xs},$line->{ys});
				
				delete $lines_hash{$n};
				unshift @return,$line;
			}
			elsif (abs($xs - $line->{xe}) < 0.0001 && abs($ys - $line->{ye}) < 0.0001){
				($xs,$ys) = ($line->{xs},$line->{ys});
				delete $lines_hash{$n};
				unshift @return,$line;
			}
		}
	}
	
	$last_count = 0;
	while($last_count != scalar(keys %lines_hash)){
		$last_count = scalar(keys %lines_hash);
		foreach my $n (keys %lines_hash){
			my $line = $lines_hash{$n};
			if (abs($xe - $line->{xs}) < 0.0001 && abs($ye - $line->{ys}) < 0.0001){
				($xe,$ye) = ($line->{xe},$line->{ye});
				delete $lines_hash{$n};
				push @return,$line;
			}
			elsif (abs($xe - $line->{xe}) < 0.0001 && abs($ye - $line->{ye}) < 0.0001){
				($line->{xs},$line->{ys},$line->{xe},$line->{ye}) =
				($line->{xe},$line->{ye},$line->{xs},$line->{ys});
				$line->{direction} = ($line->{direction} eq 'cw') ? 'ccw' : 'cw';
				($xe,$ye) = ($line->{xe},$line->{ye});
				delete $lines_hash{$n};
				push @return,$line;
			}
		}
	}
	return @return;
}

#pcbpdm里层是存的数字，为了兼容要转为tlname
sub imp_layernum2tlname {
	my $iLyrNum = shift;
	my $ret;
	if ($iLyrNum == 1) {
		$ret = "top";
	}elsif ($iLyrNum == $LayerCount) {
		$ret = "bottom";
	}elsif($iLyrNum){
		$ret = "l".$iLyrNum;
	}
	return $ret;
}

sub _um2mil{
	my $value = shift;
	return ($value/25.4);
}

