//
//Author			: walk.ly  
//Time			: 2009-05-08
//Version		: 1.0.0
//Description	: 图根导线量平差 	
//

#ifndef __ADJ_TRANSIT_
#define __ADJ_TRANSIT_

#ifdef _VS_WALK
#include "wkClassDefine.h"
#endif

#include "度分秒与弧度转换.cpp"


//计算改正数，并处理凑整误差
bool AdjV(array &vs, array &pwr, double f, int dec, bool byPower)
{
	vs.removeAll();
	int count=pwr.getSize();
	double sumPwr=Sum(pwr);
	for (int i=0; i<count; i++)
		if (byPower)
			vs.add(round5(-f/sumPwr*Double(pwr[i]), dec));
		else
			vs.add(round5(-f/count, dec));

	//*** 处理凑整误差
	double fr=Sum(vs)+f;
	AdjRoundError(pwr, vs, fr, dec);

	//验证改正数
	double sumV=Sum(vs);
	if (abs(f+sumV)>0.1/pow(10, dec))
	{
		string msg;
		msg.format("闭合差=%lf, 改正数和=%lf\n二者应绝对值相等!", f, sumV);
		message(msg);
		return false;
	}
	return true;
}

//坐标推算
bool CalCoords(double bgn, double end, array &dd, array &vs, array &res)
{
	res.removeAll(); res.add(bgn);
	double t;
	for (int i=0; i<dd.getSize(); i++)
	{
		t=Double(res[i])+Double(dd[i])+Double(vs[i]);
		res.add(t);
	}
	if (abs(t-end)>0.000001)
	{
		string msg;
		msg.format("终点的计算值=%lf, 已知值=%lf\n二者值不相等!", t, end);
		message(msg);
		return false;
	}
	return true;
}


/****************************************************
	全局变量
****************************************************/
int cooDec=3;	//坐标和边长小数后有效位数
int secDec=0;	//角度和方位角的秒值有效位数

array ptNames;	//导线点名
array obsA;		//角度观测值（以度为单位）
array obsD;		//距离观测值

array vsA;		//角度改正数（整秒数）
array adjA;		//改正后角度（以度为单位）

array adjT;		//改正后方位角（以度为单位）

array dsN, dsE;		//dN,dE坐标增量
array vsN, vsE;	//dN,dE 改正数
array cooN, cooE;	//导线点坐标

double bgnE, bgnN;	//起点坐标
double endE, endN;	//终点坐标
double bgnT, endT;	//起始方位角、终止方位角（以度为单位）

bool bLeftA=true;	//观测角在导线前进方向的左侧

double f, fa;		//角度闭合差和允许误差
double fN, fE, fD;		//坐标闭合差
double k, limK=2000;	//全长相对闭合差分母和允许误差


//计算角度改正数，并处理凑整误差
bool AdjustAngle()
{
	int aCount=obsA.getSize();	//观测角个数
	if (aCount==0)
		return false;

	//【2】计算方向闭合差 ===================================
	f=CalTs(bgnT, obsA, bLeftA)-endT;
	f=round5(f*3600.0, secDec);//以秒表示方向闭合差

	//容许误差(秒): 60 * sqrt(n)
	fa=round5(60.0*sqrt(aCount), secDec);
	if (abs(f)>fa)
	{
		string msg;
		msg.format("闭合差=%lf, 容许误差=%lf\n误差超限!", f, fa);
		message(msg);
		return false;
	}

	//【3】计算角度改正数 =======================================
	if (!AdjV(vsA, obsA, f, secDec, false))
		return false;

	//【4】计算改正后方位角 =====================================
	double t=bgnT;
	for (int i=0; i<aCount; i++)
	{
		//改正后角度
		adjA.add(Double(obsA[i])+Double(vsA[i])/3600.0);
		t=CalT(t, adjA[i], bLeftA);
		adjT.add(t);
	}
	//验证终点方位角
	if (abs(t-endT)>1e-6)
	{
		string msg;
		msg.format("终点的计算T=%lf, 已知T=%lf\n二者值不相等!", t, endT);
		message(msg);
		return false;
	}
	return true;
}

bool AdjustCoords()
{
	//计算坐标增量
	for (int i=0; i<obsD.getSize(); i++)
	{
		double dE, dN;
		ptor(obsD[i], deg_rad(adjT[i]), dN, dE);
		dsN.add(round5(dN, cooDec));
		dsE.add(round5(dE, cooDec));
	}
	//计算全长相对闭合差
	double sumN=Sum(dsN);
	double sumE=Sum(dsE);
	double sumD=Sum(obsD);
	fN = round5(sumN - (endN-bgnN), cooDec);
	fE = round5(sumE - (endE-bgnE), cooDec);
	fD = round5(sqrt(fN*fN + fE*fE), cooDec);
	k  = fD>0.001? round5(sumD/fD, 0): 1000000;

	//全长相对闭合差应<1/2000
	if (k<=limK)
	{
		string msg;
		msg.format("全长相对闭合差=1/%.0lf, 容许误差=1/%.0lf\n误差超限!", k, limK);
		message(msg);
		return false;
	}

	//求改正数
	if (!AdjV(vsN, obsD, fN, cooDec, true) ||
		!AdjV(vsE, obsD, fE, cooDec, true))
		return false;

	//求改正后坐标
	if (!CalCoords(bgnN, endN, dsN, vsN, cooN) ||
		!CalCoords(bgnE, endE, dsE, vsE, cooE))
		return false;

	return true;
}

//输出计算成果
void Output()
{
	string fileName="c:\\transitRes.txt";
	wkFile fp;
	fp.open(fileName, "wt");

	string msg;
	msg=       "|===========================================================================================================|\n"; fp.puts(msg);
	msg=       "|点名|  观测角 |  v |  改正角 |  方位角 |  距离  |   ⊿N  |   ⊿E  |  vN |  vE |    N坐标  |    E坐标  |点名|\n"; fp.puts(msg);
	msg=       "|----|---------|----|---------|---------|--------|--------|--------|-----|-----|-----------|-----------|----|\n"; fp.puts(msg);
	msg.format("|    |---------|----|---------|%9.4lf|        |        |        |     |     |-----------|-----------|----|\n",
				deg_dms(bgnT, secDec)); fp.puts(msg);
	int n=ptNames.getSize(), d=cooDec, s=secDec;
	double p=pow(10,d);
	for (int i=0; i<n; i++)
	{
		msg.format("|%4s|%9.4lf|%4.0lf|%9.4lf|---------|--------|--------|--------|-----|-----|%11.*lf|%11.*lf|%4s|\n",
				ptNames[i], deg_dms(obsA[i], s), vsA[i], deg_dms(adjA[i], s), d, cooN[i], d, cooE[i], ptNames[i]);
		fp.puts(msg);
		if (i<n-1)
		{
			msg.format("|----|---------|----|---------|%9.4lf|%8.*lf|%8.*lf|%8.*lf|%+5.0lf|%+5.0lf|-----------|-----------|----|\n",
						deg_dms(adjT[i], s), d,obsD[i], d,dsN[i], d,dsE[i], Double(vsN[i])*p, Double(vsE[i])*p);
		}else
		{
			msg.format("|    |---------|----|---------|%9.4lf|        |        |        |     |     |-----------|-----------|----|\n", deg_dms(endT, s)); fp.puts(msg);
			msg=       "|----|---------|----|---------|---------|--------|--------|--------|-----|-----|-----------|-----------|----|\n"; fp.puts(msg);
			msg.format("|合计|%9.4lf|%4.0lf|%9.4lf|%9.4lf|%8.*lf|%8.*lf|%8.*lf|%+5.0lf|%+5.0lf|%11.*lf|%11.*lf|    |\n",
						deg_dms(Sum(obsA), s), Sum(vsA), deg_dms(Sum(adjA), s),
						deg_dms(AdjAngle0_360(endT-bgnT)+(n-2)*180, s), d,Sum(obsD), d,Sum(dsN), d,Sum(dsE),
						Sum(vsN)*pow(10,d), Sum(vsE)*pow(10,d), d, endN-bgnN, d, endE-bgnE);
		}
		fp.puts(msg);
	}
	msg=       "|-----------------------------------------------------------------------------------------------------------|\n"; fp.puts(msg);
	msg.format("| 观测角为：%s角                                  坐标闭合差 fN=%6.*lf 米,   fE=%6.*lf 米,   fD=%6.*lf 米   |\n", (bLeftA? "左":"右"), d,fN, d,fE, d,fD); fp.puts(msg);
	msg.format("| 方向闭合差 f  =%6.0lf 秒                                         全长相对闭合差k=1/%6.0lf                 |\n", f, k); fp.puts(msg);
	msg.format("| 容许闭合差 f容=%6.0lf 秒                                         容许相对闭合差k=1/%6.0lf                 |\n", fa, limK); fp.puts(msg);
	msg=       "|                          f<f容，观测成果满足规范要求，可以平差                                            |\n"; fp.puts(msg);
	msg.format("|%107s|\n", " "); fp.puts(msg);
	msg=       "| 注：方向闭合差按观测角反号平均分配；  坐标闭合差按导线段长度成正比反号分配                                |\n"; fp.puts(msg);
	msg=       "|===========================================================================================================|\n"; fp.puts(msg);

	fp.close();

	//使用记事本显示结果
	wkView view;
	view.shell("notepad "+fileName);
}

//导线平差
void AdjustTransit()
{
	//【1】方位闭合差调整
	if (!AdjustAngle())
		return ;

	//【2】坐标闭合差调整
	if (!AdjustCoords())
		return ;

	//【3】输出结果
	Output();
}

#endif //__ADJ_TRANSIT_
