/*
NAME: 
DESCRIPTION: ;
PARAMETER:
    [
		{
			name : 'step',
			title : 'step',
			type : 'LineEdit',
			property : {tool_tip : '目标step,默认是orig'},
		},
		{
			name : 'outline',
			title : 'outline',
			type : 'LineEdit',
			property : {tool_tip : '目标outline,默认是ol'},
		},
		{
			name : 'units',
			title : '单位',
			type : 'RadioBox',
			property : {
				size_policy:'Expanding,Fixed',
				item_list:[
					{name:'inch',text:'INCH'},
					{name:'mm',text:'MM'},
				],
				tool_tip:'工作单位，未设定，默认为INCH'
			},
			pack : {row:1,column:1},
		},
		{
			name : 'cover_layer_suffix',
			title : '文字套层后缀',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'cover_size',
			title : '文字套层套值',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'ss_to_sm',
			title : '文字距离阻焊',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'ss_to_smd',
			title : '文字距离SMD',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'ss_to_bga',
			title : '文字距离bga',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'silk_suffix',
			title : '分离的文字层后缀',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'text_height',
			title : '文字最大高度',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'bk_suffix',
			title : '备份层后缀',
			type : 'LineEdit',
			property : {tool_tip : ''},
		},
		{
			name : 'select_lyr',
			title : '选择层别',
			type : 'RadioBox',
			property : {
				size_policy:'Expanding,Fixed',
				item_list:[
					{name:'yes',text:'Yes'},
					{name:'no',text:'No'},
				],
				tool_tip:'未设定，默认为Yes'
			},
			pack : {row:1,column:1},
		},
		{
            name : 'auto_save',
			title : '自动保存',
            type : 'RadioBox',
            property : {
				item_list:[
					{name:'yes',text:'YES'},
					{name:'no',text:'NO'},
				],
				tool_tip:'是否自动保存料号开关'
			}
        }
	]
	
 VERSION_HISTORY:
	V1.00 2020-09-01 Scott Sun
	    1.新版本
		
 HELP:
 	<html><body bgcolor="#DDECFE">
		<font size="3" color="#003DB2"><p>功能简介</p></font>
		<p> 标题 </p>
		<br>
		<font size="3" color="#003DB2"><p>参数配置</p></font>
		<p> step信息 </p>
		<br>
		<font size="3" color="#003DB2"><p>注意事项</p></font>
		<p> 无 </p>
		<br>
	</body></html>	
*/
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
console.log("=============================:template");
// 引入模块 包
var $ = require('topcam.scriptfunc').argv();
var fs = require('fs');
var _ = require('lodash');
require("topsin.genmath")
var genMath = new GenMath();
var mode = $.ikm ? "topcam" : "aimdfm";
var IKM = $.ikm; 
if (IKM==undefined ) { IKM = require('topcam.ikm6')($) }
var GEN = $.gen;
var GUI = require('topsin.gengui').newGui(require('topsin.gengui').__dirname);
var Job = $.job || $.job_name;
var JobId = $.job_id;
var db = $.db || IKM.db
var PAR = {}
if ($.par) { PAR = $.par } else if ($.hasOwnProperty('script_parameter')){ PAR = JSON.parse($.script_parameter); }
if (mode === "aimdfm") {
	var database = require("topsin.database");
	database.addConnection($.conf.database_conf, "DFM");
	var QDfm = database.query("DFM");
	$.QDfm = QDfm;
	if ($.conf.product_type == "aimdfm") {
		QDfm.updateRow({ table: "pdm_aimdfm_task", data: { current_process_title: $.process_title }, where: { id: $.task_id } });
	}
}
var Status = 'ok';
var resultData = [];
var par = PAR;
var default_par = {
	units:"mm",
	ss_to_sm: 10,		// 文字距离阻焊
	ss_to_smd: 10,		// 文字距离SMD
	ss_to_bga: 10,		// 文字距离bga
	cover_size:0,
	text_height: 1,   // 文字最大高度
	bk_suffix: "_bk",  // 备份层后缀
	silk_suffix: "_font", // 分离的文字层后缀
	cover_layer_suffix: "_cover",
	tol: 1,
	select_lyr: "no",
    step: "orig",
	auto_save: "No",
	outline: "ol"
}
for(var key in default_par){ if (!par.hasOwnProperty(key) || par[key] == ""){ par[key] = default_par[key] }}
var job = Job;
var outline = par.outline
var gui = new NewGUI(GUI);
if(!par.outline_size){
    par.outline_size  =  par.units == 'inch' ? 7.87 : 200;
}
try {
	if(_.isEmpty(job)){throw "参数job不存在"} else { job = job.toLowerCase() }
	if(!GEN.isJobExists({job:job})){throw "料号"+job+"不存在"}
	if(!GEN.isJobOpen({job:job})){ GEN.openJob({job:job}) }
    if(mode == "aimdfm"){ if(GEN.checkInout({job:job,mode:"test"}) != 0){ throw "the job check" } else { GEN.checkInout({job:job,mode:"out"}) } }

	var workstep = getWorkStep()
	if(!Array.isArray(workstep)){throw "工作step错误"}

    var err = createCoverLayer({workstep:workstep})  // 创建套层
	if (err) {throw err}
	GEN.PAUSE("createCoverLayer end; please check")

	var err = ssFrameSeparate({workstep:workstep}) // 分离文字和文字框
	if (err) {throw err}
	GEN.PAUSE("ssFrameSeparate end; please check")

	var err = slBoxOptimize({workstep:workstep}) // 文字框优化
	if (err) {throw err}

	var err = slOptimize({workstep:workstep}) // 文字优化
	if (err) {throw err}
	GEN.PAUSE("slOptimize end; please check")

	


	// 保存 
	if(/yes/ig.test(par.auto_save)){GEN.checkInout({job:job,mode:"out"}); GEN.saveJob({ job: job });GEN.checkInout({job:job,mode:"in"});GEN.closeJob({job:job});} else {GEN.checkInout({job:job,mode:"in"})}
	if (mode === "aimdfm") {
		$.QDfm.updateRow({table: "pdm_aimdfm_task",data: {progress: 33.33},where: { id: $.task_id }});
		if (GEN.hasError()) { Status = 'error';resultData.push({ type: "error", title: "GEN错误!", detail: [{ desc: _.join(GEN.STATUS, "\n") }] });
			return {status: Status,result_data: resultData};
		} else { resultData.push({ type: "info", title: "操作完成, 请注意检查!" }); return {status: Status,result_data: resultData}; }
	}else { return "Done" }
} catch (e) {
	IKM.msg(_.join(GEN.STATUS, "\n"));IKM.msg(e);Status = 'error';
    resultData.push({type: "error", title: "脚本执行出错!", detail: [{desc: _.toString(e)}]});
    return (mode === "aimdfm") ? {status: Status, result_data: resultData} : "Error";
}

// 创建套层
function createCoverLayer (props){
	// 1. step过滤
	var workstep = props.workstep;
	// 2.过滤工作层
	var work_layer = getLayer({layer_type:"silk_screen", context: "board"})
	if(/yes/ig.test(par.select_lyr)){
		var matrix = GEN.getMatrix({job:job});
		var layers = Object.keys(matrix).map(function(key){
			var tmp  ={};
			tmp[key] = key;
			return tmp
		})
		work_layer = gui.selectMultiple({title: "请先择工作层",list: layers,defaultvalue: work_layer,columns: 4,gen: GEN})	
	}
	if(work_layer.length == 0 ) {return "没有先择layer"}
	// 其他参数
	var info = gui.showForm({
		title : '请手动匹配以下信息',
		showcheck : 1,gen:GEN,
		defaultsize:[200,100],
		ui: {
			type: 'ScrollArea',
			property: { widget_resizable: true, frame_shape: 'NoFrame', align: 'Top' },
			child: {
				type: 'VBoxLayout',
				property: { margin: 2, spacing: 5, align: 'Top' },
				pack: { stretch: 0 },
				child:[{
					type: "FormGridLayout",
                    property: { columns: 1, label_alignment: 'Top | Right', margin: 10, spacing: 20 },
                    pack: { stretch: 0 },
					child:[{
						name : 'ss_to_sm',
						pack: { label: '文字距离阻焊(单边)' },
						type : 'LineEdit',
						units:par.units == 'inch' ? 'mil' : 'um',
						setter: function(obj){ obj.setText() },
						property: { enabled: true, value:par.ss_to_sm }
					},
					{
						name : 'ss_to_smd',
						pack: { label: '文字距离SMD(单边)' },
						type : 'LineEdit',
						setter: function(obj){ obj.setText() },
						units:par.units == 'inch' ? 'mil' : 'um',
						property: { value:par.ss_to_smd,enabled: true }
					},
					{
						name : 'ss_to_bga',
						pack: { label: '文字距离BGA(单边)' },
						setter: function(obj){ obj.setText() },
						type : 'LineEdit',
						value:par.ss_to_bga,
						units:par.units == 'inch' ? 'mil' : 'um',
						property: {value:par.ss_to_smd, enabled: true }
					},
					{
						type: "stretch"
					}]
				}]
			}
		},
		buttons:[{
			stock: "ok",
			sensitive: true,
			command: function (data) { }
		},
		{
			stock: "cancel",
			sensitive: true,
			command: function (ddata) { }
		},
		{
			stock: "help",
			sensitive: true,
			command: function (data) { }
		}]
	});
	if(!info){throw "未填写参数"}
	info = JSON.parse(JSON.stringify(info))
	var matrix = GEN.getMatrix({job:job})
	workstep.forEach(function(step){
		GEN.openStep({job:job,name:step});
		GEN.clearLayers();
		GEN.affectedLayer({ mode:'all',affected:'no' });
		GEN.units({ type:par.units} );
		GEN.zoomHome();
		work_layer.forEach(function(layer){
			var cover_lyr = layer + par.cover_layer_suffix ;
			var sm,outer ;
			if ( GEN.isLayerExists({job:job,layer:cover_lyr}) ) { GEN.deleteLayer({job:job,layer:[cover_lyr]}) }
			if (matrix[layer].side == 'top') {
				sm = getLayer({layer_type:"solder_mask", context:"board", side:"top"})[0]; 
				outer = getLayer({layer_type:"signal", context:"board", side:"top"})[0]; 
				GEN.createLayer({job:job,layer:cover_lyr,context:'board',type:'document',before:layer,delete_exists:'yes'});
			}else{
				sm = getLayer({layer_type:"solder_mask", context:"board", side:"bottom"})[0]; 
				outer = getLayer({layer_type:"signal", context:"board", side:"bottom"})[0]; 
				GEN.createLayer({job:job,layer:cover_lyr,context:'board',type:'document',before:layer,delete_exists:'yes'});
			}
			if ( GEN.isLayerExists({job:job,layer:sm}) ) {
				GEN.affectedLayer({affected:'yes',layer:[sm],clear_before:'yes'});
				GEN.selectByFilter({polarity:'positive',profile:'all'});
				GEN.selCopyOther({dest:'layer_name',target_layer:cover_lyr,invert:'no',size:2*info.ss_to_sm});
			}
			if ( GEN.isLayerExists({job:job,layer:outer}) ) {
				GEN.affectedLayer({affected:'yes',layer:[outer],clear_before:'yes'});
				GEN.selectByFilter({attribute:['.smd'],profile:'all'});
				if ( GEN.getSelectCount() > 0 ){GEN.selCopyOther({dest:'layer_name',target_layer:cover_lyr,invert:'no',size:2*info.ss_to_smd});}
				GEN.selectByFilter({attribute:['.bga'],profile:'all',});
				if ( GEN.getSelectCount() > 0 ){GEN.selCopyOther({dest:'layer_name',target_layer:cover_lyr,invert:'no',size:2*info.ss_to_bga});}
			}
			if ( GEN.isLayerExists({job:job,layer:outline}) ) {
				var outline_tmp = outline + '_tmp_tl';
				GEN.copyLayer({source_job:job,source_step:step,source_layer:outline,dest_layer:outline_tmp,mode:'replace',invert:'no'}) ;
				GEN.affectedLayer({affected:'yes',layer:[outline_tmp],clear_before:'yes'});
				GEN.selectByFilter({feat_types:'line\;arc',polarity:'positive',profile:'all'});
				if ( GEN.getSelectCount() > 0 ){ GEN.selChangeSym({symbol:'r'+par.outline_size}) }
				GEN.copyLayer({source_job:job,source_step:step,source_layer:outline_tmp,dest_layer:cover_lyr,mode:'append',invert:'no'})    
				GEN.deleteLayer({job:job,layer:[outline_tmp],step:step});
			}
		})
	})
	GEN.affectedLayer({affected:'no',mode:'all'})
	GEN.clearLayers()
}
// 字符 和 文字框分开
function ssFrameSeparate (props) {
	// 1. step过滤
	var workstep = props.workstep;
	// 2.过滤工作层
	var work_layers = getLayer({layer_type:"silk_screen", context: "board"})
	if(/yes/ig.test(par.select_lyr)){
		var matrix = GEN.getMatrix({job:job});
		var layers = Object.keys(matrix).map(function(key){
			var tmp  ={};
			tmp[key] = key;
			return tmp
		})
		work_layers = gui.selectMultiple({defaultsize:[200,100],title: "请先择工作层",list: layers,defaultvalue: work_layers,columns: 4,gen: GEN})	
	}
	if(work_layers.length == 0 ) {return "没有先择layer"}

	var info = gui.showForm({
		title : '请手动匹配以下信息',
		showcheck : 1,gen:GEN,
		defaultsize:[500,250],
		ui: {
			type: 'ScrollArea',
			property: { widget_resizable: true, frame_shape: 'NoFrame', align: 'Top' },
			child: {
				type: 'VBoxLayout',
				property: { margin: 2, spacing: 5, align: 'Top' },
				pack: { stretch: 0 },
				child:[{
					type: "FormGridLayout",
                    property: { columns: 1, label_alignment: 'Top | Right', margin: 10, spacing: 20 },
                    pack: { stretch: 0 },
					child:[{
						name : 'text_height',
						pack: {label : '文字最大高度'},
						type : 'LineEdit',
						setter: function(obj){ obj.setText() },
						property: { value:par.text_height * 1000,enabled: true },
						units:par.units == 'inch' ? 'mil' : 'um'
					},{
						name : 'type',
						pack: { label: '类型' },
						type : 'RadioBox',
						property: { enabled: true,item_list:[{name : 'separate', text:'字框分离'},{name:"change",text:"字框切换"}]}
					},
					{
						type: "stretch"
					}]
				}]
			}
		},
		buttons:[{
			stock: "ok",
			sensitive: true,
			command: function (data) { }
		},
		{
			stock: "cancel",
			sensitive: true,
			command: function (ddata) { }
		},
		{
			stock: "help",
			sensitive: true,
			command: function (data) { }
		}]
	});
	if(!info){throw "未填写参数"}
	info = JSON.parse(JSON.stringify(info));
	if(info.type == ""){info.type = "separate"}
	var matrix = GEN.getMatrix({job:job})
	workstep.forEach(function(step){
		GEN.openStep({job:job,name:step});
		GEN.clearLayers();
		GEN.affectedLayer({ mode:'all',affected:'no'} );
		GEN.units({ type:par.units });
		GEN.zoomHome();
		var layer_count = GEN.getLayerCount({job:job}) // IKM.get_jobinfo({jobid: JobId, jobinfo: "layer_count"})
		GEN.COM('disp_off');
		if (info["type"] == 'separate') {
			work_layers.forEach(function(layer){
				// 备份文字层
				var bk = layer + par.bk_suffix; 
				GEN.copyLayer({source_job:job,source_step:step,source_layer:layer,dest_layer:bk,mode:'replace', invert:'no'}) 
				// 分离出的文字层
				var ss_text = layer + par.silk_suffix;
				if (matrix[layer]["side"] == 'top') {
					GEN.createLayer({job:job,layer:ss_text,context:'board',type:'document',before:layer,delete_exists:'yes'});
				}else{
					GEN.createLayer({job:job,layer:ss_text,context:'board',type:'document',after:layer,delete_exists:'yes'});
				}
				
				// 开始分离文字
				GEN.affectedLayer({affected:'yes',layer:layer,clear_before:'yes'});
				GEN.COM("filter_reset,filter_name=popup");
				GEN.selectByFilter({feat_types:'line\;arc',polarity:'positive',profile:'all'});
				if ( GEN.getSelectCount() > 0 ){
					var ss_line_arc = layer + '_line_arc_tl_script';
					selCopyOther({layer:ss_line_arc,delExist: true})
					GEN.affectedLayer({affected:'yes',layer:ss_line_arc,clear_before:'yes'});
					GEN.selChangeSym({symbol:'r0.2'});
					GEN.COM("filter_reset,filter_name=popup");
					GEN.selectByFilter({feat_types:'line',polarity:'positive',profile:'all'});
					//将直线固定角度分离去除
					var ss_line = layer + '_line_tl_script';
					if ( GEN.getSelectCount() > 0 ){
						selCopyOther({layer:ss_line,delExist: true})
						GEN.affectedLayer({affected:'yes',layer:ss_line,clear_before:'yes'});
						var angle = [];
						var tol = 0.2;
						if(GEN.GEN_TYPE == 'genesis'){
							angle = [-180,-135,-90,-45,0,45,90,135];
						}else{
							angle = [0,45,90,135,180,225,270,315];
						}
						angle.forEach(function(angl){
							if(GEN.GEN_TYPE == 'genesis'){
								var min_angle = (angl-tol < -180) ? -180 : (angl-tol);
								var max_angle = (angl+tol > 180) ? 180 : (angl+tol);
								GEN.COM('filter_set',{filter_name:'popup',update_popup:'yes',slot:'line',slot_by:'angle',min_angle:min_angle,max_angle:max_angle});
							}else{
								GEN.COM('set_filter_angle',{direction:'ccw',max_angle:angl+tol,min_angle:angl-tol,slot:'lines'});
								GEN.COM("adv_filter_set,ccw_rotations=,filter_name=popup,mirror=any,bound_box=no,active=yes,srf_values=no,srf_area=no,limit_box=no");
							}
							GEN.COM("filter_area_strt");
							GEN.COM("filter_area_end,filter_name=popup,operation=select");  
						})
						if ( GEN.getSelectCount() > 0 ){GEN.selDelete()}
					}
					if(GEN.isLayerExists({job:job,layer:ss_line})){
						// 利用制作的套层
						var cover_lyr = layer + par.cover_layer_suffix;
						GEN.affectedLayer({affected:'yes',layer:[cover_lyr],clear_before:'yes'});
						GEN.COM("filter_reset,filter_name=popup");
						GEN.COM("filter_set,filter_name=popup,update_popup=no,include_syms=r*");
						GEN.COM("filter_set,filter_name=popup,update_popup=no,exclude_syms=rect*");
						GEN.COM("filter_area_strt");
						GEN.COM("filter_area_end,filter_name=popup,layer=,operation=select,inside_area=no,intersect_area=no,area_type=none");
						GEN.COM("filter_reset,filter_name=popup");
						GEN.COM("sel_reverse");
						var cover_lyr_2 = cover_lyr + '_tmp_tl';

						if ( GEN.getSelectCount() > 0 ){
							GEN.createLayer({job:job,layer:cover_lyr_2,delete_exists:'yes'});
							GEN.selCopyOther({target_layer:cover_lyr_2,invert:'no'});
						}
						GEN.affectedLayer({affected:'yes',layer:[ss_line_arc],clear_before:'yes'});
						GEN.selContourize();
						if(GEN.GEN_TYPE == 'incam'){
							GEN.COM("reset_filter_criteria,filter_name=,criteria=all");
						}else{
							GEN.COM("filter_atr_reset,filter_name=ref_select");
						}
						GEN.COM("sel_ref_feat,pads_as=shape,mode=touch,exclude_syms=,include_syms=,use=filter,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,layers="+ss_line);
						var layer_tmp1 = layer + '_tmp1_tl';
						if ( GEN.getSelectCount() > 0 ){
							GEN.createLayer({job:job,layer:layer_tmp1,delete_exists:'yes'});
							GEN.selMoveOther({target_layer:layer_tmp1,invert:'no'});
						}
						if(GEN.GEN_TYPE == 'incam'){
							GEN.COM("reset_filter_criteria,filter_name=,criteria=all");
						}else{
							GEN.COM("filter_atr_reset,filter_name=ref_select");
						}
						GEN.COM("sel_ref_feat,pads_as=shape,mode=touch,exclude_syms=,include_syms=,use=filter,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,layers="+cover_lyr_2);
						var layer_tmp2 = layer + '_tmp2_tl';
						if ( GEN.getSelectCount() > 0 ){
							GEN.createLayer({job:job,layer:layer_tmp2,delete_exists:'yes'});
							GEN.selCopyOther({target_layer:layer_tmp2,invert:'no'});
						}
						GEN.COM("sel_clean_surface,max_fold_len=0,clean_size="+info.text_height+",clean_mode=x_and_y,accuracy=0");
						if (GEN.isLayerExists({job:job,layer:"layer_tmp2"})) {
							GEN.affectedLayer({affected:'yes',layer:[layer_tmp2],clear_before:'yes'});
							if(GEN.GEN_TYPE == 'incam'){
								GEN.COM("reset_filter_criteria,filter_name=,criteria=all");
							}else{
								GEN.COM("filter_atr_reset,filter_name=ref_select");
							}
							GEN.COM("sel_ref_feat,pads_as=shape,mode=disjoint,exclude_syms=,include_syms=,use=filter,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,layers="+ss_line_arc);
							if ( GEN.getSelectCount() > 0 ){
								GEN.selMoveOther({target_layer:layer_tmp1,invert:'no'});
							}	
						}
						if (GEN.isLayerExists({job:job,layer:layer_tmp1})) {
							GEN.affectedLayer({affected:'yes',layer:[layer_tmp1],clear_before:'yes'});
							if(GEN.GEN_TYPE == 'incam'){
								GEN.COM("reset_filter_criteria,filter_name=,criteria=all");
							}else{
								GEN.COM("filter_atr_reset,filter_name=ref_select");
							}
							GEN.COM("sel_ref_feat,pads_as=shape,mode=touch,exclude_syms=,include_syms=,use=filter,f_types=line\;pad\;surface\;arc\;text,polarity=negative,layers="+layer);
							if ( GEN.getSelectCount() > 0 ){GEN.selDelete() };
							
							GEN.affectedLayer({affected:'yes',layer:[layer],clear_before:'yes'});
							if(GEN.GEN_TYPE == 'incam'){
								GEN.COM("reset_filter_criteria,filter_name=,criteria=all");
							}else{
								GEN.COM("filter_atr_reset,filter_name=ref_select");
							}
							GEN.COM("sel_ref_feat,pads_as=shape,mode=touch,exclude_syms=,include_syms=,use=filter,f_types=line\;pad\;surface\;arc\;text,polarity=positive\;negative,layers="+layer_tmp1);
							if ( GEN.getSelectCount() > 0 ){
								GEN.selMoveOther({target_layer:ss_text,invert:'no'});
							}
						}
						// 将文字属性挑选
						GEN.COM("filter_reset,filter_name=popup");
						GEN.selectByFilter({feat_types:'text'} );
						if ( GEN.getSelectCount() > 0 ){
							GEN.selMoveOther({target_layer:ss_text,invert:'no'});
						}
						delLayer([ss_line_arc,ss_line,cover_lyr_2,layer_tmp1,layer_tmp2]);
					}
				}
			})
		}
		GEN.COM("disp_on")
		var ref_layers = work_layers.filter(function(layer){ return GEN.isLayerExists({job:job, layer:layer + par.silk_suffix}) }).map(function(layer){
			return {
				work_layer: layer,
				ref_layer: layer + par.silk_suffix
			}
		})
		if(ref_layers.length > 0) {
			ref_layers.forEach(function(layerInfo){
				GEN.affectedLayer({affected:'no',mode:'all'})
				GEN.clearLayers()
				var work_layer = layerInfo.work_layer;
				var ref_layer = layerInfo.ref_layer;
				IKM.msg(work_layer+"层字框分离");
				GEN.workLayer({name:work_layer,display_number:1,clear_before:'yes'});
				if(correct(work_layer)){ var tmp = work_layer; work_layer = ref_layer,ref_layer = tmp; }
				GEN.displayLayer({name:ref_layer,number:2});
				var flag = true;
				IKM.msg("请选择需移动的文字或者的文字框，不需制作了请【左键框选空白处】")
				while(flag){
					var tmp_con = GEN.MOUSE({type:'r',text:"Please Select"});
					GEN.COM("filter_area_strt")
					GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
					GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
					GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
					if(GEN.getSelectCount() > 0){
						if(correct(work_layer)){ var tmp = work_layer; work_layer = ref_layer,ref_layer = tmp; }
						GEN.selSubstitute({tol:1,mode:'select'});
						GEN.selMoveOther({target_layer:ref_layer,invert:'no'});
					} else {
						flag = false;
					}
				}
			})
		}
	})
}
// 文字框按阻焊扩大
function slBoxOptimize(props){
	// 1. step过滤
	var workstep = props.workstep;
	// 2.过滤工作层
	var work_layers = getLayer({layer_type:"silk_screen", context: "board"})
	if(/yes/ig.test(par.select_lyr)){
		var matrix = GEN.getMatrix({job:job});
		var layers = Object.keys(matrix).map(function(key){
			var tmp  ={};
			tmp[key] = key;
			return tmp
		})
		work_layers = gui.selectMultiple({defaultsize:[200,100],title: "请先择工作层",list: layers,defaultvalue: work_layers,columns: 4,gen: GEN})	
	}
	if(work_layers.length == 0 ) {return "没有先择layer"}

	var matrix = GEN.getMatrix({job:job})
	workstep.forEach(function(step){
		var units = par.units;
		GEN.openStep({job:job,name:step});
		GEN.units({ type:units });
		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();
		var ref_layers = work_layers.filter(function(layer){ return GEN.isLayerExists({job:job, layer:layer + par.cover_layer_suffix}) }).map(function(layer){
			return {
				work_layer: layer,
				ref_layer: layer + par.cover_layer_suffix
			}
		})


		if(ref_layers.length > 0) {
			ref_layers.forEach(function(layerInfo){ // {"work_layer":"gto","ref_layer":"gto_cover"}
				GEN.affectedLayer({affected:'no',mode:'all'})
				GEN.clearLayers()
				var work_layer = layerInfo.work_layer;
				var ref_layer = layerInfo.ref_layer;
				var tmp1 = 'tl_script_tmp1', tmp2 = "tl_script_tmp2";
				delLayer([tmp1, tmp2]);
				// 放大
				var ref_pad = "tmp_ref_pad"; delLayer([ref_pad]);
				GEN.createLayer({job:job,layer:ref_pad,context:'misc',type:'document'});

				var flag = true;
				IKM.msg(work_layer + "层：请选择需放大的文字框，不需制作了请【左键框选空白处】")
				while(flag){
					GEN.workLayer({name:work_layer,display_number:1,clear_before:'yes'});
					GEN.displayLayer({name:ref_layer,number:2});
					var tmp_con = GEN.MOUSE({type:'r',text:"Please Select"});
					GEN.workLayer({name:work_layer,display_number:1,clear_before:'yes'});
					GEN.COM("filter_area_strt")
					GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
					GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
					GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
					if(GEN.getSelectCount() > 0){
						selCopyOther({layer: tmp1})
						// 判断特殊倾斜情况
						var layer_feature = GEN.getFeatures({job:job,step:step,layer:tmp1})
						// [{"type":"line","xs":"2.6998077","ys":"3.321854","xe":"2.6998077","ye":"3.4104367","symbol":"r7","polarity":"positive","attributes":[]},{"type":"line","xs":"2.6998077","ys":"3.321854","xe":"2.8912643","ye":"3.321854","symbol":"r7","polarity":"positive","attributes":[]},{"type":"line","xs":"2.6998077","ys":"3.4104367","xe":"2.8912643","ye":"3.4104367","symbol":"r7","polarity":"positive","attributes":[]},{"type":"line","xs":"2.8912643","ys":"3.321854","xe":"2.8912643","ye":"3.4104367","symbol":"r7","polarity":"positive","attributes":[]}]
						// 1.算出最长边的角度
						var angle = getAngle(layer_feature)
						if (angle %90 == 0) {angle = 0}
						if (angle < 0){angle = 90 + angle}
						// 求中心点
						GEN.workLayer({name:ref_layer,display_number:1,clear_before:'yes'});
						var layer_limits_tmp1 = GEN.getLayerLimits({job:job,step:step,layer:tmp1,units:units});
						GEN.selectByFilter({area_rect:{x1:layer_limits_tmp1.xmin-0.01,y1:layer_limits_tmp1.ymin-0.01,x2:layer_limits_tmp1.xmax+0.01,y2:layer_limits_tmp1.ymax+0.01}});
						selCopyOther({layer: "tmp_center"})
						var layer_limits_tmp = GEN.getLayerLimits({job:job,step:step,layer:"tmp_center",units:units});
						layer_limits_tmp.xc = layer_limits_tmp.xmin - 0 + layer_limits_tmp.xsize/2;
						layer_limits_tmp.yc = layer_limits_tmp.ymin - 0 + layer_limits_tmp.ysize/2;
						delLayer("tmp_center")
						GEN.clearLayers()
						GEN.affectedLayer({affected:'no',mode:'all'})
						GEN.affectedLayer({affected:'yes',layer:[work_layer,tmp1]})
						GEN.COM("filter_area_strt")
						GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
						GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
						GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
						// 更具角度将其旋转
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:layer_limits_tmp.xc,y_anchor:layer_limits_tmp.yc,angle:angle})
						GEN.affectedLayer({affected:'no',mode:'all'})
						GEN.workLayer({name:ref_layer,display_number:1,clear_before:'yes'});
						GEN.selectByFilter({area_rect:{x1:layer_limits_tmp1.xmin-0.01,y1:layer_limits_tmp1.ymin-0.01,x2:layer_limits_tmp1.xmax+0.01,y2:layer_limits_tmp1.ymax+0.01}});
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:layer_limits_tmp.xc,y_anchor:layer_limits_tmp.yc,angle:angle})
						
						GEN.copyLayer({source_job:job,source_step:step,source_layer:tmp1,dest_layer:tmp2,mode:'replace',invert:'no'});
						var text_tmp = 'tl_tmp_text';
						GEN.copyLayer({source_job:job,source_step:step,source_layer:tmp1,dest_layer:text_tmp,mode:'replace',invert:'no'});
						var layer_limits = GEN.getLayerLimits({job:job,step:step,layer:text_tmp,units:units});
						layer_limits.xc = layer_limits.xmin - 0 + layer_limits.xsize/2;
						layer_limits.yc = layer_limits.ymin - 0 + layer_limits.ysize/2;
						var scalex=1,scaley=1;
						GEN.affectedLayer({affected:'yes',layer:[ref_layer],clear_before:'yes'});
						GEN.selectByFilter({area_rect:{x1:layer_limits.xmin-0.01,y1:layer_limits.ymin-0.01,x2:layer_limits.xmax+0.01,y2:layer_limits.ymax+0.01}});
						if ( GEN.getSelectCount() > 0 ){
							GEN.selCopyOther({target_layer:ref_pad,invert:'no'});
							var layer_limits_pad = GEN.getLayerLimits({job:job,step:step,layer:ref_pad,units:units});
							var feature = GEN.getFeatures({job:job,step:step,layer:tmp1,units:units});
							var line_width = feature[0].symbol.slice(1) / 1000;
							var tmp_ps = 0.004;
							if (units == "mm"){tmp_ps = tmp_ps*25.4}
// {"layer_limits_pad":{"xmin":"68.6901125","ymin":"84.4900925","xmax":"73.310115","ymax":"86.5100925",
// "xsize":4.620002499999998,"ysize":2.019999999999996},"line_width":0.1778,
// "layer_limits":{"xmin":"68.486215","ymin":"84.2861925","xmax":"73.527","ymax":"86.714",
// "xsize":5.040785,"ysize":2.4278075,"xc":71.0066075,"yc":85.50009625}}
							scalex = (Number(layer_limits_pad.xsize)+line_width*2+tmp_ps)/(layer_limits.xsize);
							if(scalex < 1) {scalex = 1 }
							scaley = (Number(layer_limits_pad.ysize)+line_width*2+tmp_ps)/(layer_limits.ysize);
							if(scaley < 1) {scaley = 1 }
						}
						delLayer(text_tmp)
						GEN.affectedLayer({affected:'yes',layer:[tmp1],clear_before:'yes'});
						GEN.selTransform({mode:'anchor',oper:'scale',x_anchor:layer_limits_tmp.xc,y_anchor:layer_limits_tmp.yc,x_scale:scalex,y_scale:scaley}) 
						// {"mode":"anchor","oper":"scale","x_anchor":71.0066075,"y_anchor":85.50009625,"x_scale":1,"y_scale":1}
						// 检查是否含单根线
						// var tmp = 'tl-'+tmp1+'tmp1++';
						// var _tmp2 = 'tl-'+tmp1+'tmp2++';
						// var tmp3 = 'tl-'+tmp1+'-alone';
						// var cale_x = scalex;  // ?
						// var cale_y = scaley;  // ?
						// GEN.createLayer({job:job,layer:tmp,context:'misc',type:'document',delete_exists:'yes'});
						// GEN.createLayer({job:job,layer:tmp3,context:'misc',type:'document',delete_exists:'yes'});

						// GEN.selCopyOther({target_layer:tmp,invert:'no'});
						// GEN.affectedLayer({affected:'yes',mode:'single',layer:tmp,clear_before:'yes'});
						// GEN.selContourize();

						// GEN.DO_INFO("-t layer -e "+job+"/"+step+"/"+tmp+" -d FEAT_HIST");
						
						// if (GEN.INFO_RESULT.gFEAT_HISTsurf > 0) {
						// 	for(var i=1;i <= GEN.INFO_RESULT.gFEAT_HISTsurf;i++){
						// 		GEN.createLayer({job:job,layer:_tmp2,context:'misc',type:'document',delete_exists:'yes'});
						// 		GEN.affectedLayer({affected:'yes',mode:'single',layer:tmp,clear_before:'yes'});
						// 		GEN.COM('sel_layer_feat',{operation:'select',layer:tmp,index:i});
						// 		GEN.selCopyOther({target_layer:_tmp2,invert:'no'});
						// 		GEN.affectedLayer({affected:'yes',mode:'single',layer:_tmp2,clear_before:'yes'});
						// 		GEN.COM('sel_surf2outline',{width:1});
						// 		GEN.COM('filter_reset',{filter_name:'popup'});
						// 		GEN.selectByFilter({feat_types:'arc',polarity:'positive',profile:'all'});
						// 		if (GEN.getSelectCount() > 0) {GEN.selDelete() } ;
						// 		var feat = GEN.getFeatures({job:job,step:step,layer:_tmp2});
						// 		var hash = {};
						// 		for(var i=0;i < feat;i++){
						// 			for(var k = i+1;k < feat.length; k++){
						// 				if ((feat[i].xs == feat[k].xs && feat[i].ys == feat[k].ys) ||
						// 					(feat[i].xs == feat[k].xe && feat[i].ys == feat[k].ye) ){
						// 						if(!hash[i+'star']){hash[i+'star'] = {}}
						// 						hash[i+'star'][x] = feat[i].xs;
						// 						hash[i+'star'][y] = feat[i].ys;
						// 				}
						// 				if ((feat[i].xe == feat[k].xs && feat[i].ye == feat[k].ys) ||
						// 					(feat[i].xe == feat[k].xe && feat[i].ye == feat[k].ye)) {
						// 						if(!hash[i+'end']){hash[i+'end'] = {}}
						// 						hash[i+'end'][x] = feat[i].xe;
						// 						hash[i+'end'][y] = feat[i].ye;
						// 				}
						// 			}
						// 		}
						// 		if (Object.keys(hash).length == 0) {
						// 			GEN.affectedLayer({affected:'yes',mode:'single',layer:tmp1,clear_before:'yes'});
						// 			GEN.selRefFeat({layers:_tmp2,use:'filter',mode:'touch'});
						// 			if ( GEN.getSelectCount() > 0 ){
						// 				GEN.COM('sel_move_other',{target_layer:tmp3,invert:'no',dx:0,dy:0,size:0,x_anchor:0,y_anchor:0,rotation:0,mirror:'none'});
						// 				var change_scal_x = (1 / cale_x).toFixed(3) - 0;
						// 				var change_scal_y = (1 / cale_y).toFixed(3) - 0;
						// 				GEN.affectedLayer({affected:'yes',mode:'single',layer:tmp3,clear_before:'yes'});
						// 				GEN.selTransform({mode:'axis',oper:'scale',x_anchor:0,y_anchor:0,x_scale:change_scal_x,y_scale:change_scal_y});
						// 				// {"mode":"axis","oper":"scale","x_anchor":0,"y_anchor":0,"x_scale":1,"y_scale":1}
						// 				GEN.COM('sel_move_other',{target_layer:tmp1,invert:'no',dx:0,dy:0,size:0,x_anchor:0,y_anchor:0,rotation:0,mirror:'none'});
						// 				GEN.deleteLayer({job:job,layer:tmp3,step:step});
						// 			}
						// 		}
						// 	}
						// 	GEN.deleteLayer({job:job,layer:_tmp2,step:step});
						// 	GEN.deleteLayer({job:job,layer:tmp,step:step});
						// }else{
						// 	GEN.deleteLayer({job:job,layer:tmp,step:step});
						// 	if (GEN.isLayerEmpty({job:job,step:step,layer:tmp3})) {
						// 	GEN.deleteLayer({job:job,layer:tmp3,step:step});
						// 	}
						// }


						// 转回去
						GEN.clearLayers()
						GEN.affectedLayer({affected:'yes',layer:[work_layer,tmp1,tmp2], clear_before:"yes"})
						GEN.COM("filter_area_strt")
						GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
						GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
						GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:layer_limits_tmp.xc,y_anchor:layer_limits_tmp.yc,angle:360-angle})
						GEN.affectedLayer({affected:'no',mode:'all'})
						GEN.workLayer({name:ref_layer,display_number:1,clear_before:'yes'});
						if(GEN.isLayerExists({ job:job,step:step,layer:ref_pad})){GEN.affectedLayer({affected:'yes',layer:ref_pad})}
						GEN.selectByFilter({area_rect:{x1:layer_limits_tmp1.xmin-0.01,y1:layer_limits_tmp1.ymin-0.01,x2:layer_limits_tmp1.xmax+0.01,y2:layer_limits_tmp1.ymax+0.01}});
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:layer_limits_tmp.xc,y_anchor:layer_limits_tmp.yc,angle:360-angle})

						GEN.workLayer({name:tmp1,display_number:1,clear_before:'yes'});
						GEN.displayLayer({name:work_layer,number:2});
						if(!GEN.isLayerEmpty({ job:job,step:step,layer:ref_pad})){GEN.displayLayer({name:ref_layer,number:3})}
						GEN.COM('disp_on');
						if(GEN.isLayerExists({ job:job,step:step,layer:ref_pad})){GEN.deleteLayer({job:job, layer:ref_pad})}
						var ans = GEN.PAUSE('Please Check...');
						if(!/ok/ig.test(ans)){ throw "cancel" }
						GEN.COM('disp_off');


						var tmp_symbol = 'tl_script_tmp';
						GEN.workLayer({name:tmp1,display_number:1,clear_before:'yes'});
						GEN.COM('sel_all_feat');
						GEN.COM( "sel_create_sym,symbol="+tmp_symbol+",x_datum=0,y_datum=0,delete=no,fill_dx=0.1,fill_dy=0.1,attach_atr=no,retain_atr=no" );
						GEN.workLayer({name:work_layer,display_number:1,clear_before:'yes'});
						GEN.selRefFeat({layers:tmp2,use:'filter',mode:'cover'});
						GEN.COM( "sel_substitute,mode=substitute,symbol="+tmp_symbol+",tol="+par.tol+",x_datum=0,y_datum=0,dcode=0" );
						GEN.selectByFilter({include_syms:tmp_symbol});
						if ( GEN.getSelectCount() > 0 ){GEN.selBreak()};
						GEN.COM('disp_on');
						GEN.COM('truncate_layer', {layer :tmp1});
						GEN.COM('truncate_layer', {layer :tmp2});
						GEN.COM('disp_on');
						GEN.COM('sel_clear_feat');
						GEN.units({type:units});
					} else {
						flag = false;
					}
				}
			})
		}
	})
	if(GEN.isLayerExists({job:job, layer:"tmp_ref_pad"})){GEN.deleteLayer({job:job, layer:["tmp_ref_pad"]})}

}

// 文字放大
function slOptimize(props) {

	var info1 = gui.showForm({
		title : '请手动匹配以下信息',
		showcheck : 1,gen:GEN,
		defaultsize:[200,100],
		ui: {
			type: 'ScrollArea',
			property: { widget_resizable: true, frame_shape: 'NoFrame', align: 'Top' },
			child: {
				type: 'VBoxLayout',
				property: { margin: 2, spacing: 5, align: 'Top' },
				pack: { stretch: 0 },
				child:[{
					type: "FormGridLayout",
                    property: { columns: 1, label_alignment: 'Top | Right', margin: 10, spacing: 20 },
                    pack: { stretch: 0 },
					child:[{
						name : 'font_symbol',
						pack: { label: '文字symbol' },
						type : 'LineEdit',
						setter: function(obj){ obj.setText() },
						units: 'um',
						property: { enabled: true, value:"200" }
					},
					{
						name : 'x_scale',
						pack: { label: '文字距离x方向放大倍数' },
						type : 'LineEdit',
						setter: function(obj){ obj.setText() },
						property: { value:1,enabled: true }
					},
					{
						name : 'y_scale',
						pack: { label: '文字距离y方向放大倍数' },
						setter: function(obj){ obj.setText() },
						type : 'LineEdit',
						property: {value:1.2, enabled: true }
					},
					{
						type: "stretch"
					}]
				}]
			}
		},
		buttons:[{
			stock: "ok",
			sensitive: true,
			command: function (data) { }
		},
		{
			stock: "cancel",
			sensitive: true,
			command: function (ddata) { }
		},
		{
			stock: "help",
			sensitive: true,
			command: function (data) { }
		}]
	});
	if(!info1){throw "未填写参数"}
	info1 = JSON.parse(JSON.stringify(info1))
	var x_scale1 = info1.x_scale;
	var y_scale1 = info1.y_scale;
	// 1. step过滤
	var workstep = props.workstep;
	// 2.过滤工作层
	var work_layers = getLayer({layer_type:"silk_screen", context: "board"})
	if(/yes/ig.test(par.select_lyr)){
		var matrix = GEN.getMatrix({job:job});
		var layers = Object.keys(matrix).map(function(key){
			var tmp  ={};
			tmp[key] = key;
			return tmp
		})
		work_layers = gui.selectMultiple({defaultsize:[200,100],title: "请先择工作层",list: layers,defaultvalue: work_layers,columns: 4,gen: GEN})	
	}
	if(work_layers.length == 0 ) {return "没有先择layer"}

	var matrix = GEN.getMatrix({job:job})

	workstep.forEach(function(step) {
		GEN.openStep({job:job, name:step})
		GEN.units({type:par.units})
		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();
		work_layers.forEach(function(layer){
			var font_layer = layer + par.silk_suffix;
			GEN.workLayer({name:font_layer,display_number:2,clear_before:'yes'})

			GEN.selClearFeature()
			GEN.selectByFilter({feat_types:"text"})
			if(GEN.getSelectCount() > 0) {
				GEN.COM("sel_break_level,attr_mode=merge")
			}

			GEN.COM("filter_set,filter_name=popup,update_popup=no,feat_types=line\;arc")
			GEN.COM("filter_area_strt")
			GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=none,inside_area=no,intersect_area=no")
			GEN.COM("filter_reset,filter_name=popup")
			GEN.selReverse()
			if(GEN.getSelectCount() > 0) {
				GEN.selMoveOther({target_layer:layer,invert:'no',dx:0,dy:0,size:0})
			}

			GEN.selChangeSym({symbol:"r" + info1.font_symbol})
			var tmp1 = font_layer + "_1";
			var tmp2 = font_layer + "_2";
			var tmp3 = font_layer + "_3";
			var bk = font_layer + "_bk";
			var bk2 = font_layer + "_ok";
			[tmp1,tmp2,tmp3,bk,bk2].forEach(function(v){
				if(GEN.isLayerExists({job:job, layer:v})){GEN.deleteLayer({job:job,layer:[v]})}
			})
			// GEN.copyLayer({source_job:job,source_step:step,source_layer:font_layer,dest_layer:tmp1, mode:"replace"})
			GEN.copyLayer({source_job:job,source_step:step,source_layer:font_layer,dest_layer:tmp3, mode:"replace"})
			GEN.copyLayer({source_job:job,source_step:step,source_layer:font_layer,dest_layer:bk2, mode:"replace"})
			// GEN.copyLayer({source_job:job,source_step:step,source_layer:font_layer,dest_layer:bk, mode:"replace"})
			GEN.affectedLayer({affected:'no',mode:'all'})
			GEN.selClearFeature()
			// GEN.workLayer({name:tmp1,display_number:2,clear_before:'yes'})
			// GEN.selChangeSym({symbol:"r0.1"})

			// 利用tmp3 快速定位
			GEN.workLayer({name:tmp3,display_number:2,clear_before:'yes'})
			GEN.units({type:"mm"})
			GEN.selChangeSym({symbol:"r1000"})
			// 转铜皮  获取每一个铜皮的limits信息
			GEN.selContourize()
			var fast_features = GEN.getFeatures({job:job,step:step,layer:tmp3,options:"feat_index",surface:1,units:"mm"})
			fast_features = featsToLimits(fast_features)
			fast_features.forEach(function(item){
				if(item.limit.xsize > item.limit.ysize) {
					item.x_scale = x_scale1
					item.y_scale = y_scale1
				} else {
					item.y_scale = x_scale1
					item.x_scale = y_scale1
				}
			})
			fast_features.forEach(function(item){
				GEN.workLayer({name:bk2,display_number:2,clear_before:'yes'})
				GEN.COM("filter_area_strt")
				GEN.COM("filter_area_xy,x="+item.limit.xmin+",y=" + item.limit.ymin)
				GEN.COM("filter_area_xy,x="+item.limit.xmax+",y=" + item.limit.ymax)
				GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=yes")
				if(GEN.getSelectCount() > 0 ) {
					GEN.selTransform({mode:'anchor',oper:'scale',x_anchor: item.limit.xc,y_anchor: item.limit.yc,x_scale:item.x_scale,y_scale:item.y_scale}) 
				}
			})

			var flag = true;
			IKM.msg(font_layer + "层：请选择需放大的文字，不需制作了请【左键框选空白处】")
			while(flag){
				var bk2_tmp = bk2 + "_tmp"
				GEN.workLayer({name:font_layer,display_number:1,clear_before:'yes'});
				var tmp_con = GEN.MOUSE({type:'r',text:"Please Select"});

				var info = gui.showForm({
						title : '请手动匹配以下信息',
						showcheck : 1,gen:GEN,
						defaultsize:[200,100],
						ui: {
							type: 'ScrollArea',
							property: { widget_resizable: true, frame_shape: 'NoFrame', align: 'Top' },
							child: {
								type: 'VBoxLayout',
								property: { margin: 2, spacing: 5, align: 'Top' },
								pack: { stretch: 0 },
								child:[{
									type: "FormGridLayout",
									property: { columns: 1, label_alignment: 'Top | Right', margin: 10, spacing: 20 },
									pack: { stretch: 0 },
									child:[{
										name : 'font_symbol',
										pack: { label: '文字symbol' },
										type : 'LineEdit',
										setter: function(obj){ obj.setText() },
										units: 'um',
										property: { enabled: true, value:"200" }
									},
									{
										name : 'x_scale',
										pack: { label: '文字距离x方向放大倍数' },
										type : 'LineEdit',
										setter: function(obj){ obj.setText() },
										property: { value:1,enabled: true }
									},
									{
										name : 'y_scale',
										pack: { label: '文字距离y方向放大倍数' },
										setter: function(obj){ obj.setText() },
										type : 'LineEdit',
										property: {value:1.2, enabled: true }
									},
									{
										type: "stretch"
									}]
								}]
							}
						},
						buttons:[{
							stock: "ok",
							sensitive: true,
							command: function (data) { }
						},
						{
							stock: "cancel",
							sensitive: true,
							command: function (ddata) { }
						},
						{
							stock: "help",
							sensitive: true,
							command: function (data) { }
						}]
					});
				if(!info){throw "未填写参数"}
				info = JSON.parse(JSON.stringify(info))
				var x_scale = info.x_scale;
				var y_scale = info.y_scale;

				GEN.workLayer({name:font_layer,display_number:1,clear_before:'yes'});
				GEN.COM("filter_area_strt")
				GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
				GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
				GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
				if(GEN.getSelectCount() > 0){
					var tmp_layer = font_layer + "_tmp";
					selCopyOther({delExist:true,layer: tmp_layer})
					GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'});
					GEN.selAllFeat()
					selCopyOther({delExist:true,layer: bk2_tmp})
					GEN.workLayer({name:bk2,display_number:1,clear_before:'yes'});
					GEN.COM("filter_area_strt")
					GEN.COM("filter_area_xy,x="+tmp_con.x1+",y="+tmp_con.y1)
					GEN.COM("filter_area_xy,x="+tmp_con.x2+",y="+tmp_con.y2)
					GEN.COM("filter_area_end,layer=,filter_name=popup,operation=select,area_type=rectangle,inside_area=yes,intersect_area=no")
					if(GEN.getSelectCount() > 0) {GEN.selDelete()}
					GEN.workLayer({name:tmp_layer,display_number:1,clear_before:'yes'});
					var limits = GEN.getLayerLimits({job:job,step:step,layer:tmp_layer, units:"mm"})
					for (var key in limits) {
						limits[key] = limits[key] - 0;
					}
					limits.xc = limits.xmin + limits.xsize/2
					limits.yc = limits.ymin + limits.ysize/2

					// 获取里面有几个字母 每一个字母的limits信息
					GEN.selChangeSym({symbol:"r1"})
					GEN.selContourize()
					var feas = GEN.getFeatures({job:job,step:step,layer:tmp_layer,options:"feat_index",units:"mm"})
					if(feas.length == 1) {
						GEN.workLayer({name:bk2_tmp,display_number:2,clear_before:'yes'});
						GEN.selTransform({mode:'anchor',oper:'scale',x_anchor:limits.xc,y_anchor:limits.yc,x_scale:x_scale,y_scale:y_scale}) 
						GEN.selMoveOther({target_layer:bk2,invert:'no',dx:0,dy:0,size:0}) 
					} else if (feas.length > 1) {
						var limits_info = [];
						feas.forEach(function(item) {
							var index = item.index;
							GEN.selLayerFeat({layer:tmp_layer, index:index,operation:"select"});
							if(GEN.getSelectCount() > 0) {
								var tmp_l = GEN.getLayerLimits({job:job,step:step,layer:tmp_layer, units:"mm", options:"select"})
								for (var key in tmp_l) {
									tmp_l[key] = tmp_l[key] - 0;
								}
								tmp_l.xc = tmp_l.xmin + tmp_l.xsize/2
								tmp_l.yc = tmp_l.ymin + tmp_l.ysize/2
								limits_info.push({index:index, limits:tmp_l })
								GEN.selClearFeature()
							}
						})
						var rodata = []
						limits_info.forEach(function (item, i) {
							if(limits_info[i+1]){
								rodata.push(getRodate({
									xs : item.limits.xc,
									ys : item.limits.yc,
									xe : limits_info[i+1].limits.xc,
									ye : limits_info[i+1].limits.yc
								}))
							}
						})
						var angle = rodata.reduce(function(a,b) {return a + b}) / rodata.length;
						if (Math.abs(angle) < 10) { angle = 0 }
						GEN.workLayer({name:bk2_tmp,display_number:2,clear_before:'yes'});
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:limits.xc,y_anchor:limits.yc,angle:angle})
						// 按照中心放大
						var limits2 = GEN.getLayerLimits({job:job,step:step,layer:tmp_layer, units:"mm"})
						for (var key in limits) {
							limits2[key] = limits2[key] - 0;
						}
						limits2.xc = limits2.xmin + limits2.xsize/2
						limits2.yc = limits2.ymin + limits2.ysize/2
						if(limits2.xsize > limits2.ysize) {
							limits2.x_scale = x_scale
							limits2.y_scale = y_scale
						} else {
							limits2.y_scale = x_scale
							limits2.x_scale = y_scale
						}
						GEN.selTransform({mode:'anchor',oper:'scale',x_anchor:limits2.xc,y_anchor:limits2.yc,x_scale:limits2.x_scale,y_scale:limits2.y_scale}) 
						GEN.selTransform({mode:'anchor',oper:"rotate",x_anchor:limits.xc,y_anchor:limits.yc,angle:360 - angle})
						GEN.selMoveOther({target_layer:bk2,invert:'no',dx:0,dy:0,size:0}) 
					}
					GEN.deleteLayer({job:job, layer:[tmp_layer]})
				} else {
					flag = false
				}
				if(GEN.isLayerExists({job:job, layer:bk2_tmp})) {
					GEN.deleteLayer({job:job, layer:[bk2_tmp]})
				}
			}

			// 将ok的移动到文字层
			GEN.workLayer({name:font_layer,display_number:2,clear_before:'yes'});
			GEN.selDelete();
			GEN.workLayer({name:bk2,display_number:2,clear_before:'yes'});
			GEN.selMoveOther({target_layer:font_layer,invert:'no',dx:0,dy:0,size:0});
			GEN.workLayer({name:font_layer,display_number:2,clear_before:'yes'});
			GEN.selMoveOther({target_layer:layer,invert:'no',dx:0,dy:0,size:0});
			[tmp1,tmp2,tmp3,bk,bk2,"_ok","_fail",font_layer].forEach(function(v){
				if(GEN.isLayerExists({job:job, layer:v})){GEN.deleteLayer({job:job,layer:[v]})}
			});

			var cover_lyr = layer + par.cover_layer_suffix ;
			if(GEN.isLayerExists({job:job, layer:cover_lyr})){
				GEN.workLayer({name:cover_lyr,display_number:2,clear_before:'yes'});
				GEN.selMoveOther({target_layer:layer,invert:"yes",dx:0,dy:0,size:par.cover_size});
			}

		})
	})
}	

function selCopyOther(props){ // {layer , invent,  dx, dy , size}
    if(GEN.getSelectCount()>0){ if(!props || !props.layer){return}
        if(props.delExist){if(GEN.isLayerExists({job:job, layer:props.layer})){GEN.deleteLayer({job:job, layer:[props.layer]})}}
        GEN.selCopyOther({dest:'layer_name',target_layer:props.layer,invert:props.invert || 'no',dx:props.dx || 0,dy:props.dy || 0,size:props.size || 0})
    }
}

function getLayer(props){
    if(!props){return}
    if(!props.context){props.context = "board"}
    var matrix = GEN.getMatrix({job:job})
    return Object.keys(matrix).reduce(function(a,b){
        var info = matrix[b];
        var ret = true;
        for (var key in props) { if(!Array.isArray(props[key])){props[key] = [props[key]]}
        if(info[key] && props[key].indexOf(info[key]) < 0){ ret = false } }
        if(ret){  a.push(props.res == "info"? info : b) } return a
    },[])
}

function NewGUI (gui) {
    this.msgBox = function(props){ // title  type  content  button
        props = props || {}
        return gui.msgBox(props.title || "title",props.type || "info",props.content || "content",props.button || ["ok", "cancel"]);
    }
    this.selectFromTreeview = gui.selectFromTreeview
    this.confirm = function(props) {
        props = props || {}
        return gui.confirm(props.content || "content",props.button || ["yes", "no"], props.type || "question");
    }
    this.selectFile = function(props){ // "choose something", "*", true, "file", "/home/abby/fast_io"
        props = props || {}
        return gui.selectFile(props.title || "choose something",props.filter || "*",props.multiple || false, "file","");
    }
    this.selectSingle = function(props) {
        props = props || {}
        return gui.selectSingle({
            "title": props.title || "select",
            "list": props.list || [],
            "default": props["default"] || "",
            "columns": props.columns || 2,
            "gen":props.gen || GEN
        });
    }
    this.selectMultiple = function(props) {
        props = props || {}
        return gui.selectMultiple({
            "title": props.title || "select",
            "list": props.list || [],
            "defaultvalue": props["defaultvalue"] || [""],
            "defaultsize": props["defaultsize"] || [200, 100],
            "columns": props.columns || 2,
            "gen":props.gen || GEN
        });
    }
    this.selectFromTable = gui.selectFromTable
    this.snapScreen = gui.snapScreen
    this.imageViewer = gui.imageViewer
    this.inputBox = gui.inputBox
    this.showForm = gui.showForm
    this.selectLayer = function(props){
        props = props || {}
        return gui.selectLayer({
            title: props.title || "请选择层",
            filter: props.filter || ".*", // regular expression
            selectmode: props.selectmode || "multiple", // single, multiple
            context: props.context || "all", // all, board, misc
            layertype: props.layertype || "signal", // default type of layertypelist
            defaultsize: props.defaultsize || [600, 400], // window size
            layermatrix: props.layermatrix || props.matrix,
            layertypelist: props.layertypelist || [
                {name: "all", display_name: "all", filter: function(x) { return x }},
                {name: "signal", display_name: "signal", filter: function(x) { return x["layer_type"] === "signal"; }},
                {name: "power_ground", display_name: "power_ground", filter: function(x) { return x["layer_type"] === "power_ground"; }},
                {name: "mixed", display_name: "mixed", filter: function(x) { return x["layer_type"] === "mixed"; }},
                {name: "solder_mask", display_name: "solder_mask", filter: function(x) { return x["layer_type"] === "solder_mask"; }},
                {name: "silk_screen", display_name: "silk_screen", filter: function(x) { return x["layer_type"] === "silk_screen"; }},
                {name: "solder_paste", display_name: "solder_paste", filter: function(x) { return x["layer_type"] === "solder_paste"; }},
                {name: "drill", display_name: "drill", filter: function(x) { return x["layer_type"] === "drill"; }},
                {name: "rout", display_name: "rout", filter: function(x) { return x["layer_type"] === "rout"; }},
                {name: "document", display_name: "document", filter: function(x) { return x["layer_type"] === "document"; }}
            ],
            gen: props.GEN || GEN
        })
    } 
    this.lockUnlockLayer = function(props){
        props = props || {}
        var tmp = {}
        if (props.matrix) {
            for (var key in props.matrix) {
                var item = props.matrix[key]
                tmp[key] = {
                    row : item.row,
                    name : item.name
                }
            }
        }
        return gui.lockUnlockLayer({
            title: props.title || "lockUnlockLayer",
            layermatrix:props.layermatrix || tmp 
        })
    } 
    this.passwordBox = function(props){
        props = props || {}
        return gui.passwordBox({title:props.title || "password", password:props.password || "1212"})
    } 
    this.selectJobLayer = function (props) {
        props = props || {}
        return gui.selectJobLayer({
            layertypelist: props.layertypelist || [
                {name: "all", display_name: "all", filter: function(x) { return x }},
                {name: "signal", display_name: "signal", filter: function(x) { return x["layer_type"] === "signal"; }},
                {name: "power_ground", display_name: "power_ground", filter: function(x) { return x["layer_type"] === "power_ground"; }},
                {name: "mixed", display_name: "mixed", filter: function(x) { return x["layer_type"] === "mixed"; }},
                {name: "solder_mask", display_name: "solder_mask", filter: function(x) { return x["layer_type"] === "solder_mask"; }},
                {name: "silk_screen", display_name: "silk_screen", filter: function(x) { return x["layer_type"] === "silk_screen"; }},
                {name: "solder_paste", display_name: "solder_paste", filter: function(x) { return x["layer_type"] === "solder_paste"; }},
                {name: "drill", display_name: "drill", filter: function(x) { return x["layer_type"] === "drill"; }},
                {name: "rout", display_name: "rout", filter: function(x) { return x["layer_type"] === "rout"; }},
                {name: "document", display_name: "document", filter: function(x) { return x["layer_type"] === "document"; }}
            ],
            //defaultlayertype: "ha",
            joblist: props.joblist || [],
            defaultJob: props.defaultJob || [], // select by default
            steplist: props.steplist || [],
            // defaultstep: "step3",
            showstep: props.showstep || true,
            selectmode: props.selectmode || "multiple", // single/multiple
            layermatrix: props.layermatrix || {  },
            defaultlayer: props.defaultlayer || []
        })
    }
}

function getWorkStep(props){
	var steplists = GEN.getStepList({job:job});
	if(steplists.length == 0){return "该料号没有step"}
	var steps_tmp = steplists.filter(function(name){
		var reg = new RegExp(par.step, "ig")
		return reg.test(name)
	})
	if(steplists.length == 0){return "根据脚本参数过滤出来的step不存在，请检查资料或者脚本参数配置！"}
	var workstep = gui.selectMultiple({
		title: "请先择工作step",
		size:[200,100],
		defaultsize:[200,100],
		list: steplists.map(function(v){ var tmp = {}; tmp[v] = v ;return tmp}),
		defaultvalue: steps_tmp,
		columns: 1,
		gen: GEN
	})
	if(workstep.length == 0 ) {return "没有先择step"}
	return workstep
}

function delLayer(layer){
	if(!Array.isArray(layer)){
		layer = [layer]
	}
	layer = layer.filter(function(v){return GEN.isLayerExists({job:job, layer:v})})
	if(layer.length){
		GEN.deleteLayer({job:job, layer:layer})
	}
}

function correct(work_layer){
	var tmp = GEN.getWorkLayer();
	return tmp !== work_layer;
}

function getAngle(features){ // 获取最长边的角度
	features.sort(function(a,b){
		a.length = getLineLength(a);
		b.length = getLineLength(b);
		return a.length - b.length
	})
	return getRodate(features[features.length - 1])
}
function getLineLength (line){
    if (line.type != "line"){return 0}
    return Math.sqrt((line.xe - line.xs)*(line.xe - line.xs) + (line.ye - line.ys)*(line.ye - line.ys)) 
}
function getRodate(props){
    var xs = props.xs;
    var ys = props.ys;
    var xe = props.xe;
    var ye = props.ye;
    var y = ye - ys;
    var x = xe - xs;
    var r = Math.atan(y / x)
    return r*180/Math.PI
}

function sameDirection(xory, type, res, indexes) {
	for (var key in xory) {
		var current = -1;
		var data = xory[key];
		data.sort(function(a,b){return a[type] - b[type]})
		data.forEach(function(item, i){
			if (i > current){
				var ret = [item];
				current = searchFont(item, data, i, ret,type)
				if(ret.length > 1) {
					ret.forEach(function(item) {
						indexes = indexes.filter(function(item2){
							return item2.index != item.index
						})
					})
					
					res.push(ret.reduce(function(a,b){
						if(Number(b.limit.xmin) < Number(a.xmin)){
							a.xmin = b.limit.xmin
						}
						if(Number(b.limit.ymin) < Number(a.ymin)){
							a.ymin = b.limit.ymin
						}
						if(Number(b.limit.xmax) > Number(a.xmax)){
							a.xmax = b.limit.xmax
						}
						if(Number(b.limit.ymax) > Number(a.ymax)){
							a.ymax = b.limit.ymax
						}
						return a
					},{
						xmin: item.limit.xmin,
						ymin: item.limit.ymin,
						xmax: item.limit.xmax,
						ymax: item.limit.ymax
					}))
				}
			}
		})
	}
	return indexes
}
function searchFont(l ,arr, i, ret, type){
	if(arr[i+1]){
		var len =  Math.abs(l[type] - arr[i+1][type])
		if(len <= 1.5){
			ret.push(arr[i+1])
			return searchFont(arr[i+1], arr, i+1, ret, type)
		} else {return i}
	}
	return i+1
}
function turnFix(data) {
	return parseFloat(data).toFixed(1)
}
function surfaceAnalysis(props){
	props.limit.xmin = props.limit.xmin - 0; 
	props.limit.ymin = props.limit.ymin - 0; 
	props.limit.xmax = props.limit.xmax - 0; 
	props.limit.ymax = props.limit.ymax - 0; 
	props.limit.xsize = props.limit.xsize - 0; 
	props.limit.ysize = props.limit.ysize - 0; 
	props.xc = props.limit.xsize / 2 + props.limit.xmin
	props.yc = props.limit.ysize / 2 + props.limit.ymin
}

function featsToLimits(feats) {
    feats.forEach(function(item) {
        if(item.feats) {
            var polygon = genMath.profile2Polygon(item.feats.join("\n"),0)
            var res = polygon.reduce(function(a,b){
                a.xmin = b.x > a.xmin ? a.xmin : b.x;
                a.ymin = b.y > a.ymin ? a.ymin : b.y;
                a.xmax = b.x < a.xmax ? a.xmax : b.x;
                a.ymax = b.y < a.ymax ? a.ymax : b.y;
                return a
            }, {
                xmin: polygon[0].x,
                ymin: polygon[0].y,
                xmax: polygon[0].x,
                ymax: polygon[0].y
            })
            res.xsize = Math.abs(res.xmax - res.xmin) 
            res.ysize = Math.abs(res.ymax - res.ymin) 
            res.xc = res.xmin + res.xsize/2
			res.yc = res.ymin + res.ysize/2
            item.limits = res
            item.limit = res
        }
    })
    return feats
}