1. Point.cs
public class Point
{
public string name;
public int num;
public double X;
public double Y;
public double x0;
public double y0;
public double LC_dobule; //离道路起点的距离
public string LC_string;
public string curveType;//所属是缓和曲线还是圆曲线
public string curveLocation;//在曲线段上的位置
public string pointType;//整数桩stakePoint or 主点桩mainPoint
//public string pointType;
}
2.Curve.cs
public class Curve
{
public double a1;//rear交点到该交点的方位角
public double a2;//该交点到front交点的方位角
public double a;//曲线偏角
public Point JD;
public double Ls;//缓和曲线长
public double R;
public Point rearJD;
public Point frontJD;
public List<Point> IntegerPilePoints;
public double m;
public double b0;
public double P;
public double E;
public double T;
public double q;
public double L;
public Point ZH;
public Point HY;
public Point QZ;
public Point YH;
public Point HZ;
public Curve()
{
IntegerPilePoints = new List<Point>();
ZH = new Point();
HY = new Point();
QZ = new Point();
YH = new Point();
HZ = new Point();
}
public Curve(Point JD,Point leftJD,Point rightJD,double ls,double r)
{
this.JD = JD;
this.rearJD = leftJD;
this.frontJD = rightJD;
this.Ls = ls;
this.R = r;
}
}
3.DataCenter.cs
public class DataCenter
{
public Point start;//线路起点
public Point end;//线路终点
public double pile_Spacing;//桩距
public List<Curve> curves;//存放所有曲线
public List<Point> totalPoints;//存放主点和整桩点的集合
public bool dataFlag;
public bool calFlag;
/// <summary>
/// 构造函数
/// </summary>
public DataCenter()
{
curves = new List<Curve>();
totalPoints = new List<Point>();
start = new Point();
end = new Point();
dataFlag = false;
calFlag = false;
}
/// <summary>
/// 生成计算报告
/// </summary>
/// <returns></returns>
public string GetReport()
{
string str = "";
str += "-----------------------------------------计算报告-----------------------------------------";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "------------------------------- 1. 统计信息 -------------------------------";
str += "\r\n";
str += "\r\n";
str += "道路总长:"+(end.LC_dobule-start.LC_dobule).ToString("F3") +"\r\n";
int m=0;
int n=0;
for (int i = 0; i < curves.Count; i++)
{
if (curves[i].JD.curveType == "YQX")
{
m++;
}
else n++;
}
str += "圆曲线数目:" + m.ToString()+ "\r\n";
str += "带有缓和曲线的圆曲线数目:" + n.ToString() + "\r\n";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "------------------------------- 2. 曲线数据 -------------------------------";
str += "\r\n";
str += "\r\n";
for (int i = 0; i < curves.Count; i++)
{
Curve cv = curves[i];
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "**************************";
str += " 第" + (i + 1).ToString() + "段道路曲线";
str += "**************************";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "---------------- ① 曲线参数 ----------------";
str += "\r\n";
str += "\r\n";
str += "交点名称:" + cv.JD.name + "\r\n";
str += "曲线类型:";
if (cv.JD.curveType=="HHQX")
{
str += "带缓和曲线的圆曲线" + "\r\n";
str += "\r\n";
str += "------------ i 缓和曲线参数 ------------" + "\r\n";
str += "切垂距m:" + cv.m.ToString("F6") + "\r\n";
str += "圆曲线内移量P:" + cv.P.ToString("F6") + "\r\n";
str += "缓和曲线切线角β0:" + cv.b0.ToString("F3") + "\r\n";
str += "\r\n";
str += "------------ ii 综合曲线要素 ------------" + "\r\n";
str += "线路转向角α(°′″):" + HelpAlgorithm.Rad2DMS(cv.a) + "\r\n";
str += "圆曲线半径R:" + cv.R.ToString("F3") + "\r\n";
str += "缓和曲线长Ls:" + cv.Ls.ToString("F3") + "\r\n";
str += "切线长T:" + cv.T.ToString("F6") + "\r\n";
str += "曲线长L:" + cv.L.ToString("F6") + "\r\n";
str += "外矢距E" + cv.E.ToString("F6") + "\r\n";
str += "切曲差q:" + cv.q.ToString("F6") + "\r\n";
}
else
{
str += "圆曲线" + "\r\n";
str += "\r\n";
str += "线路转向角α(°′″):" + HelpAlgorithm.Rad2DMS(cv.a) + "\r\n";
str += "圆曲线半径R:" + cv.R.ToString("F3") + "\r\n";
str += "切线长T:" + cv.T.ToString("F6") + "\r\n";
str += "曲线长L:" + cv.L.ToString("F6") + "\r\n";
str += "外矢距E" + cv.E.ToString("F6") + "\r\n";
str += "切曲差q:" + cv.q.ToString("F6") + "\r\n";
}
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "---------------- ② 主点里程及坐标 ----------------";
str += "\r\n";
str += "\r\n";
str += "点号 里程 X坐标 Y坐标 ";
str += "\r\n";
if (cv.JD.curveType == "HHQX")
{
str += "直缓点(ZH) " + cv.ZH.LC_string + " " + cv.ZH.X.ToString("F3") + " " + cv.ZH.Y.ToString("F3") + " "+ "\r\n";
str += "缓圆点(HY) " + cv.HY.LC_string + " " + cv.HY.X.ToString("F3") + " " + cv.HY.Y.ToString("F3") + " " + "\r\n";
str += "曲中点(QZ) " + cv.QZ.LC_string + " " + cv.QZ.X.ToString("F3") + " " + cv.QZ.Y.ToString("F3") + " " + "\r\n";
str += "圆缓点(YH) " + cv.YH.LC_string + " " + cv.YH.X.ToString("F3") + " " + cv.YH.Y.ToString("F3") + " " + "\r\n";
str += "缓直点(HZ) " + cv.HZ.LC_string + " " + cv.HZ.X.ToString("F3") + " " + cv.HZ.Y.ToString("F3") + " " + "\r\n";
str += "交 点(JD) " + cv.JD.LC_string + " " + cv.JD.X.ToString("F3") + " " + cv.JD.Y.ToString("F3") + " " + "\r\n";
str += "\r\n";
}
else
{
str += "直圆点(ZY) " + cv.ZH.LC_string + " " + cv.ZH.X.ToString("F3") + " " + cv.ZH.Y.ToString("F3") + " " + "\r\n";
str += "曲中点(QZ) " + cv.QZ.LC_string + " " + cv.QZ.X.ToString("F3") + " " + cv.QZ.Y.ToString("F3") + " " + "\r\n";
str += "圆直点(YZ) " + cv.HZ.LC_string + " " + cv.HZ.X.ToString("F3") + " " + cv.HZ.Y.ToString("F3") + " " + "\r\n";
str += "交 点(JD) " + cv.JD.LC_string + " " + cv.JD.X.ToString("F3") + " " + cv.JD.Y.ToString("F3") + " " + "\r\n";
str += "\r\n";
}
}
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "\r\n";
str += "------------------------------- 3. 定桩数据 -------------------------------";
str += "\r\n";
str += "\r\n";
str += "起点里程:" + start.LC_string + "\r\n";
str += "终点里程:" + end.LC_string + "\r\n";
str += "桩距:" + pile_Spacing.ToString() + "\r\n";
str += "\r\n";
str += "点名 里程(m) X坐标(m) Y坐标(m) 所在位置";
str += "\r\n";
for (int i = 0; i <totalPoints.Count; i++)
{
Point tmp = totalPoints[i];
if(tmp.pointType=="mainPoint")
{
str += " "+tmp.name + " " + tmp.LC_string + " " + tmp.X.ToString("F3") + " " + tmp.Y.ToString("F3") + " " + tmp.curveLocation + "\r\n";
}
else str +=tmp.name+" " +tmp.LC_string+ " " + tmp.X.ToString("F3") + " " + tmp.Y.ToString("F3") + " " +tmp.curveLocation+ "\r\n";
}
str += "\r\n";
str += "\r\n";
str += "----------------------------------------- 结束 -----------------------------------------";
return str;
}
public DataTable GetPointTable()
{
DataTable dt = new DataTable();
dt.TableName = "定桩数据表";
dt.Columns.Add("点名", typeof(string));
dt.Columns.Add("里程", typeof(string ));
dt.Columns.Add("X(m)",typeof(double));
dt.Columns.Add("Y(m)", typeof(double));
dt.Columns.Add("曲线类型", typeof(string));
int num=1;
foreach (var point in totalPoints )
{
point.num = num;
DataRow dr = dt.NewRow();
dr["点名"] = point.name;
dr["里程"] = point.LC_string;
dr["X(m)"] = point.X;
dr["Y(m)"] = point.Y;
dr["曲线类型"] = point.curveLocation;
dt.Rows.Add(dr);
num++;
}
return dt;
}
}
4.Algorithm.cs
class Algorithm
{
/// <summary>
/// 预处理,将交点链接上前后交点,方便后续计算
/// </summary>
/// <param name="curves">所有曲线的集合</param>
/// <param name="start">线路起点</param>
/// <param name="end">线路终点</param>
public static void PreProcess(ref List<Curve> curves, Point start, Point end)
{
for (int i = 0; i < curves.Count; i++)
{
if (i == 0)
{//第一个交点
curves[i].rearJD = start;
curves[i].frontJD = curves[i + 1].JD;
}
else if (i == curves.Count - 1)
{//最后一个交点
curves[i].rearJD = curves[i - 1].JD;
curves[i].frontJD = end;
}
else
{//中间交点
curves[i].rearJD = curves[i - 1].JD;
curves[i].frontJD = curves[i + 1].JD;
}
}
}
/// <summary>
/// 计算曲线要素及主点信息
/// </summary>
/// <param name="curve">单独的一个曲线</param>
public static void CalCurveFeature(ref Curve curve)
{
#region 求曲线偏角
curve.a1 = HelpAlgorithm.Calazimuth(curve.rearJD, curve.JD);//JDi-1到JDi的方位角
curve.a2 = HelpAlgorithm.Calazimuth(curve.JD, curve.frontJD);//JDi到JDi+1的方位角
double fi;
fi = curve.a2 - curve.a1;
if (-Math.PI < fi && fi < Math.PI)
curve.a = fi;
else
{
if (Math.PI <= fi && fi <= 2 * Math.PI)
curve.a = fi - 2 * Math.PI;
else
curve.a = fi + 2 * Math.PI;
}
#endregion
double R = curve.R;
double Ls = curve.Ls;
double a = Math.Abs(curve.a);
//计算曲线要素
if (curve.JD.curveType== "HHQX")
{//缓和曲线段
curve.m = Ls / 2.0 - Math.Pow(Ls, 3) / 240 / R / R+Math.Pow(Ls,5)/34560/Math.Pow (R,4);
curve.P = Ls * Ls / 24 / R - Math.Pow (Ls,4)/2688/Math.Pow (R ,3); //这两个公式可能与书上的不一样,不知道新版的书修改了没
curve.b0 = Ls / 2 / R;
curve.T = curve.m + (R + curve.P) * Math.Tan(a / 2.0);
curve.L = R * a - 2 * curve.b0 * R + 2 * Ls;
curve.E = (R + curve.P) / Math.Cos(a / 2.0) - R;
curve.q = 2 * curve.T - curve.L;//切曲差,重要!用来求交点里程
}
else
{//圆曲线段
curve.T = R * Math.Tan(a / 2.0);
curve.L = R * a;
curve.E = R / Math.Cos(a / 2.0) - R;
curve.q = 2 * curve.T - curve.L;
}
}
/// <summary>
/// 计算交点里程(此步骤书中好像没写上)
/// </summary>
/// <param name="curves">所有曲线的集合</param>
/// <param name="start">线路起点</param>
/// <param name="end">线路终点</param>
public static void CalJD_LC(ref List<Curve> curves, Point start,Point end)
{
for (int i = 0; i < curves.Count; i++)
{
if (i == 0)
{//第一个交点
curves[i].JD.LC_dobule =start.LC_dobule+ HelpAlgorithm.CalDistance(start, curves[i].JD);
}
else
{//其余交点
curves[i].JD.LC_dobule = curves[i-1].JD.LC_dobule + HelpAlgorithm.CalDistance(curves[i - 1].JD, curves[i].JD)- curves[i - 1].q;
}
}
foreach (var a in curves)
{//将交点里程转化为字符串格式存起来
a.JD.LC_string = HelpAlgorithm.LC2String(a.JD.LC_dobule);
}
//切曲差,即2倍的切线长减去曲线长。
//前一个交点桩号减去后个交点桩号不等于两交点之间的直线长度。
//设D为切曲差,L为曲线长度,T为切线长:
//则D = 2T - L,前一个交点桩号 = 前一个ZY(ZH)桩号 + T,前一个YZ(HZ)桩号 = 前一个ZY(ZH)桩号 + L,把D = 2T - L带入前式,前一个YZ(HZ)桩号 = 前一个ZY(ZH)桩号 +(D - L)/ 2
//可以看出,前一个YZ(HZ)桩号不等于前一个交点桩号 + T。现在我们分析后个交点:
//后个交点桩号 = 前一个YZ(HZ)桩号 + 中间直线长(如果中间有直线的话)+后T。那么
//后个交点桩号 - 前一个交点桩号 = 前一个YZ(HZ)桩号 + 中间直线长(如果中间有直线的话)+后T -(前一个ZY(ZH)桩号 + 前T)= 中间直线长(如果中间有直线的话)+后T + L - 前T,
//由D = 2T - L得L = 2T - D,带入上式,得:后个交点桩号 - 前一个交点桩号 = 中间直线长(如果中间有直线的话)+后T + 前T - D。
//即:
// 后个交点桩号 = 前一个交点桩号 + 交点之间的直线距离 - 前一个交点的D。(重要,题目好像没给这个式子)
//
}
/// <summary>
/// 计算曲线主点坐标及里程
/// </summary>
/// <param name="curve">单独的一个曲线</param>
public static void CalMainPoints(ref Curve curve)
{
Point ZH = new Point();//当曲线为圆曲线时,ZH点与ZY点等价
ZH.name = "ZH";
ZH.pointType = "mainPoint";//主点用mainPoint标识
ZH.LC_dobule = curve.JD.LC_dobule - curve.T;//里程
ZH.X = curve.JD.X - curve.T * Math.Cos(curve.a1);
ZH.Y = curve.JD.Y - curve.T * Math.Sin(curve.a1);
curve.ZH = ZH;
Point QZ = new Point();
QZ.name = "QZ";
QZ.pointType = "mainPoint";
QZ.curveLocation = "CircularCurve";//计算局部坐标时需要这个判断条件
QZ.LC_dobule = ZH.LC_dobule + curve.L / 2.0;
CalPointx0y0(ref QZ, ref curve);//先计算局部坐标
x0y0ToXY(ref QZ, ref curve);//再转换为测量坐标
curve.QZ =QZ;
Point HZ = new Point();//当曲线为圆曲线时,HZ点与YZ点等价
HZ.name = "HZ";
HZ.pointType = "mainPoint";
HZ.LC_dobule = ZH.LC_dobule +curve.L;
HZ.X = curve.JD.X + curve.T * Math.Cos(curve.a2);
HZ.Y = curve.JD.Y + curve.T * Math.Sin(curve.a2);
curve.HZ = HZ;
if (curve.JD.curveType== "HHQX")
{//缓和曲线有额外两个主点HY和YH
Point HY = new Point();
HY.name = "HY";
HY.pointType = "mainPoint";
HY.curveLocation = "FirstTranstionCurve";//计算局部坐标时需要这个判断条件
HY.LC_dobule = ZH.LC_dobule + curve.Ls;
CalPointx0y0(ref HY, ref curve);
x0y0ToXY(ref HY, ref curve);
curve.HY = HY;
Point YH = new Point();
YH.name = "YH";
YH.pointType = "mainPoint";
YH.curveLocation = "SecondTranstionCurve";//计算局部坐标时需要这个判断条件
YH.LC_dobule = ZH.LC_dobule + curve.L - curve.Ls;
CalPointx0y0(ref YH, ref curve);
x0y0ToXY(ref YH, ref curve);
curve.YH = YH;
}
}
/// <summary>
/// 求点的局部坐标
/// </summary>
/// <param name="tmpPoint">点</param>
/// <param name="cv">该点所属的曲线</param>
public static void CalPointx0y0(ref Point tmpPoint,ref Curve cv)
{
if (tmpPoint.curveLocation != "CircularCurve")
{//点在缓和曲线上
double Li;
if(tmpPoint.curveLocation=="FirstTranstionCurve")
{//点位于第一段缓和曲线上
Li = tmpPoint.LC_dobule - cv.ZH.LC_dobule;
}
else Li= cv.HZ.LC_dobule- tmpPoint.LC_dobule;//点位于第二段缓和曲线上
tmpPoint.x0 = Li - Math.Pow(Li, 5) / 40 / cv.R / cv.R / cv.Ls / cv.Ls;
tmpPoint.y0 = Math.Pow(Li, 3) / 6 / cv.R / cv.Ls;
}
else
{//点在圆曲线上
double Li = tmpPoint.LC_dobule - cv.ZH.LC_dobule;//当曲线为圆曲线时,ZH点与ZY点等价
double fi= cv.b0 + (Li - cv.Ls) / cv.R;
tmpPoint.x0 = cv.m + cv.R * Math.Sin(fi);
tmpPoint.y0 = cv.P + cv.R * (1-Math.Cos(fi));
}
}
/// <summary>
/// 局部坐标转化为测量坐标
/// </summary>
/// <param name="tmpPoint">点</param>
/// <param name="cv">该点所属的曲线段</param>
public static void x0y0ToXY(ref Point tmpPoint, ref Curve cv)
{
double steer;
if (cv.a > 0)
{
steer = 1;
}
else steer = -1;
double pAngle1 =cv.a1;//JDi-1 - JDi连线的方位角
double pAngle2 =cv.a2+Math.PI;JDi+1 - JDi连线的方位角(是a2的反方位角)
double ZH_X = cv.ZH.X;//直缓点的测量坐标
double ZH_Y = cv.ZH.Y;
double HZ_X = cv.HZ.X;//缓直点的测量坐标
double HZ_Y = cv.HZ.Y;
if (tmpPoint.curveLocation != "SecondTranstionCurve")
{//第一段缓和曲线及圆曲线上的点(不带缓和曲线的圆曲线时也适用,因为ZH点与ZY点等价)
tmpPoint.X = Math.Cos(pAngle1) * tmpPoint.x0 - steer * Math.Sin(pAngle1) * tmpPoint.y0 + ZH_X;
tmpPoint.Y = Math.Sin(pAngle1) * tmpPoint.x0 + steer * Math.Cos(pAngle1) * tmpPoint.y0 + ZH_Y;
}
else
{//第二段缓和曲线上的点
tmpPoint.X = Math.Cos(pAngle2) * tmpPoint.x0 + steer * Math.Sin(pAngle2) * tmpPoint.y0 + HZ_X;
tmpPoint.Y = Math.Sin(pAngle2) * tmpPoint.x0 - steer * Math.Cos(pAngle2) * tmpPoint.y0 + HZ_Y;
}
}
/// <summary>
/// 计算整桩点的测量坐标,并把主点和整桩点按顺序存起来
/// </summary>
/// <param name="curves"></param>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="step"></param>
/// <returns></returns>
public static List<Point> CalIntegerPilePoints(ref List<Curve> curves,Point start, Point end, double step)
{
//计算终点里程
end.LC_dobule = curves.Last().HZ.LC_dobule + HelpAlgorithm.CalDistance(curves.Last().HZ, end);
end.LC_string = HelpAlgorithm.LC2String(end.LC_dobule);
List<Point> totalPoint = new List<Point>();//储存路线上的点,包括主点和整桩点
double limit;
double foot;
int index = 1;//整桩点的序号
Point tagert;//目标点
#region 起点到第一个ZH/ZY点的之间的线段
foot = (start.LC_dobule / step + 1) * step;//foot调整到 离起点里程最近的整桩里程(做这一步是考虑了起点里程不是0的情形)
limit = start.LC_dobule + HelpAlgorithm.CalDistance(start, curves[0].ZH);
while (foot<=limit)
{
tagert = new Point();
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.LC_dobule = foot;
tagert.curveLocation = "Line";
tagert.X = start.X + Math.Cos(curves[0].a1) * (foot- start.LC_dobule);
tagert.Y = start.Y + Math.Sin(curves[0].a1) * (foot- start.LC_dobule);
totalPoint.Add(tagert);
foot += step;
index++;
}
#endregion
#region 中间段
for (int i = 0; i < curves.Count; i++)
{
Curve cv = curves[i];
//圆曲线
if (cv.JD.curveType=="YQX")
{
#region 圆曲线
limit = cv.HZ.LC_dobule;//当曲线为圆曲线时,HZ点与YZ点等价
bool addQZ = false;//用来标示QZ点是否被添加
totalPoint.Add(cv.ZH);
while (foot<=limit)
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
if ((!addQZ) && (tagert.LC_dobule>=cv.QZ.LC_dobule))
{//添加QZ点
totalPoint.Add(cv.QZ);
addQZ = true;
}
tagert.curveLocation = "CircularCurve";
CalPointx0y0(ref tagert, ref cv);//先计算局部坐标
x0y0ToXY(ref tagert, ref cv);//局部坐标转换为测量坐标
totalPoint.Add(tagert);
foot += step;
index++;
}
totalPoint.Add(cv.HZ);//添加YZ点
#endregion
#region 此曲线后的直线段
if (i != curves.Count - 1)
{
limit = cv.HZ.LC_dobule + HelpAlgorithm.CalDistance(cv.HZ, curves[i + 1].ZH);
while (foot <= limit)
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.curveLocation = "Line";
tagert.X = cv.HZ.X + Math.Cos(curves[i+1].a1) * (foot - cv.HZ.LC_dobule);
tagert.Y = cv.HZ.Y + Math.Sin(curves[i+1].a1) * (foot - cv.HZ.LC_dobule);
totalPoint.Add(tagert);
foot += step;
index++;
}
continue;//处理下一个交点
} else break;//到最后一个交点就终止
#endregion
}
else
{
//缓和曲线,分为三部分处理
#region 第一段缓和曲线
totalPoint.Add(cv.ZH);
while ((cv.ZH.LC_dobule <= foot) && (foot <= cv.HY.LC_dobule))
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.curveLocation = "FirstTranstionCurve";
CalPointx0y0(ref tagert, ref cv);
x0y0ToXY(ref tagert, ref cv);
totalPoint.Add(tagert);
foot += step;
index++;
}
totalPoint.Add(cv.HY);
#endregion
#region 中间的圆曲线
bool addQZ = false;
while ((cv.HY.LC_dobule <= foot) && (foot <= cv.YH.LC_dobule))
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
if ((!addQZ) && (tagert.LC_dobule >= cv.QZ.LC_dobule))
{//添加QZ点
totalPoint.Add(cv.QZ);
addQZ = true;
}
tagert.curveLocation = "CircularCurve";
CalPointx0y0(ref tagert, ref cv);
x0y0ToXY(ref tagert, ref cv);
totalPoint.Add(tagert);
foot += step;
index++;
}
totalPoint.Add(cv.YH);
#endregion
#region 第二段缓和曲线
while ((cv.YH.LC_dobule <= foot) && (foot <= cv.HZ.LC_dobule))
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.curveLocation = "SecondTranstionCurve";
CalPointx0y0(ref tagert, ref cv);
x0y0ToXY(ref tagert, ref cv);
totalPoint.Add(tagert);
foot += step;
index++;
}
totalPoint.Add(cv.HZ);
#endregion
#region 此曲线后的直线段
if (i != curves.Count - 1)
{
limit = cv.HZ.LC_dobule + HelpAlgorithm.CalDistance(cv.HZ, curves[i + 1].ZH);
while (foot <= limit)
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.curveLocation = "Line";
tagert.X = cv.HZ.X + Math.Cos(curves[i + 1].a1) * (foot - cv.HZ.LC_dobule);
tagert.Y = cv.HZ.Y + Math.Sin(curves[i + 1].a1) * (foot - cv.HZ.LC_dobule);
totalPoint.Add(tagert);
foot += step;
index++;
}
continue;//处理下一个交点
} else break;//到最后一个交点就终止
#endregion
}
}
#endregion
#region 最后一个交点的HZ/YZ到终点
Curve last = curves.Last();
limit = last.HZ.LC_dobule + HelpAlgorithm.CalDistance(last.HZ, end);
double angle = last.a2;//最后一个交点到终点的方位角
while (foot <= limit)
{
tagert = new Point();
tagert.LC_dobule = foot;
tagert.name = "Stake" + index.ToString().PadLeft(3, '0');//桩号编号
tagert.curveLocation = "Line";
tagert.X = last.HZ.X + Math.Cos(angle) * (foot - last.HZ.LC_dobule);
tagert.Y = last.HZ.Y + Math.Sin(angle) * (foot - last.HZ.LC_dobule);
totalPoint.Add(tagert);
foot += step;
index++;
}
#endregion
foreach (var a in totalPoint)
{//将里程转化为字符串格式,存起来
a.LC_string = HelpAlgorithm.LC2String(a.LC_dobule);
}
return totalPoint;
}
/// <summary>
/// 弧度转°′″
/// </summary>
/// <param name="rad">弧度</param>
/// <returns></returns>
public static string RadToDu(double rad)
{
string du;
int dd, mm;
double ss;
dd = (int)(rad * 180 / Math.PI);
mm = (int)((rad * 180 / Math.PI) % 1) * 60;
ss = ((((rad * 180 / Math.PI) % 1) * 60) % 1) * 60;
du = dd.ToString() + "°" + mm.ToString() + "′" + ss.ToString() + "″";
return du;
}
}
5.HelpAlgorithm.cs
class HelpAlgorithm
{
/// <summary>
/// 计算坐标方位角
/// </summary>
/// <param name="start">起始点</param>
/// <param name="end">终点</param>
/// <returns></returns>
public static double Calazimuth(Point start, Point end)
{
double dx;
double dy;
double Angle;
double azimuth = 0;//方位角
//1.计算象限角
dx = end.X - start.X;
dy = end.Y - start.Y;
if (dx != 0)
{
Angle = Math.Atan(Math.Abs(dy / dx));
//2.根据dx,dy正负判断所在象限
if (dx > 0 && dy > 0) azimuth = Angle;
if (dx > 0 && dy < 0) azimuth = 2 * Math.PI - Angle;
if (dx < 0 && dy < 0) azimuth = Math.PI + Angle;
if (dx < 0 && dy > 0) azimuth = Math.PI - Angle;
}
else
{
if (dy < 0) azimuth = Math.PI * 3.0 / 2.0;
else azimuth = Math.PI / 2.0;
}
return azimuth;
}
/// <summary>
/// 计算距离
/// </summary>
/// <param name="start">起点</param>
/// <param name="end">终点</param>
/// <returns></returns>
public static double CalDistance(Point start, Point end)
{
double distance;
double dx = end.X - start.X;
double dy = end.Y - start.Y;
distance = Math.Sqrt(dx * dx + dy * dy);
return distance;
}
/// <summary>
/// 将弧度制角度转为度分秒格式的字符串
/// </summary>
/// <param name="a">弧度a</param>
/// <returns>度分秒字符串</returns>
public static string Rad2DMS(double a)
{
double tmpD = Math.Abs(a) * 180 / Math.PI;
int d = (int)tmpD;
double tmp = (tmpD - d) * 3600;//得到秒数
int m = (int)(tmp / 60);
double s = tmp - m * 60;
string str = d.ToString() + "°" + m.ToString() + "′" + s.ToString("f4").PadLeft(7,'0') + "″";
return str;
}
/// <summary>
/// double型里程转换为string型
/// </summary>
/// <param name="LC">double型里程</param>
/// <returns>string型里程</returns>
public static string LC2String(double LC)
{
int a =(int)( LC / 1000.0);
double b = LC - a * 1000;
string str = "K" + a.ToString() + "+" + b.ToString("F3").PadLeft(7,'0');
return str;
}
}
6.Draw.cs
class Draw
{
public static void DrawByChart(Chart myChart, List<Point> totalPoints)
{
myChart.Annotations.Clear();//清除文字标记
myChart.Series.Clear();
myChart.ChartAreas.Clear();
#region 定义绘图区参数
ChartArea area = new ChartArea();
area.Name = "绘图区";
area.AxisX.Enabled = AxisEnabled.False;
area.AxisY.Enabled = AxisEnabled.False;
double maxX = totalPoints.Max(o => o.X);
double minX = totalPoints.Min(o => o.X);
double maxY = totalPoints.Max(o => o.Y);
double minY = totalPoints.Min(o => o.Y);
//坐标轴范围
area.AxisX.Maximum = maxY + (maxY - minY) / totalPoints.Count;
area.AxisX.Minimum = minY - (maxY - minY) / totalPoints.Count;
area.AxisY.Maximum = maxX + (maxX - minX) / totalPoints.Count;
area.AxisY.Minimum = minX - (maxX - minX) / totalPoints.Count;
//允许缩放
area.CursorX.IsUserEnabled = true;
area.CursorY.IsUserEnabled = true;
area.CursorX.IsUserSelectionEnabled = true;
area.CursorY.IsUserSelectionEnabled = true;
//无格网
area.AxisX.MajorGrid.Enabled = false;
area.AxisY.MajorGrid.Enabled = false;
myChart.ChartAreas.Add(area);
#endregion
#region 定义中桩要素
Series mainPointSr = new Series();
mainPointSr.ChartType = SeriesChartType.Point;
mainPointSr.Name = "主点桩";
mainPointSr.MarkerStyle = MarkerStyle.Circle;
mainPointSr.MarkerSize = 10;
mainPointSr.MarkerColor = System.Drawing.Color.Blue;
mainPointSr.ToolTip = " X坐标:#VALY, Y坐标:#VALX";
Series stakePointSr = new Series();
stakePointSr.LegendText = "整数桩";
stakePointSr.ChartType = SeriesChartType.Point;
stakePointSr.MarkerStyle = MarkerStyle.Circle;
stakePointSr.MarkerSize = 7;
stakePointSr.MarkerColor = System.Drawing.Color.DarkSeaGreen;
stakePointSr.ChartArea = area.Name;
stakePointSr.ToolTip = " X坐标:#VALY, Y坐标:#VALX";
foreach (var a in totalPoints)
{
DataPoint dp = new DataPoint();
dp.SetValueXY(a.Y, a.X);
if (a.pointType == "mainPoint")
{
TextAnnotation ta1 = new TextAnnotation();//新建文本
ta1.AnchorDataPoint =dp;//绑定的点
ta1.Text = a.name;//文本内容
ta1.X = dp.XValue + 0.1;//文本的位置
ta1.Y = dp.YValues[0] + 0.1;
ta1.AllowMoving = true;//允许文字移动
ta1.ForeColor = System.Drawing.Color.Black;
myChart.Annotations.Add(ta1);
mainPointSr.Points.Add(dp);
}
else stakePointSr.Points.Add(dp);
}
mainPointSr.ChartArea = area.Name;
stakePointSr.ChartArea = area.Name;
myChart.Series.Add(mainPointSr);
myChart.Series.Add(stakePointSr);
#endregion
// ControlScale(area, myChart.Width, myChart.Height);// 控制图形缩放比例
myChart.DataBind();//绑定数据
}
/// <summary>
/// 调整缩放比例,确保图形比例不失真
/// </summary>
/// <param name="area"></param>
/// <param name="wid">chart控件的宽度</param>
/// <param name="hei">chart控件的高度</param>
/// <param name="pointSr"></param>
public static void ControlScale(ChartArea area, int wid, int hei)
{
double maxX = area.AxisX.Maximum;
double minX = area.AxisX.Minimum;
double maxY = area.AxisY.Maximum;
double minY = area.AxisY.Minimum;
double r1 = (maxX - minX) / wid;
double r2 = (maxY - minY) / hei;
double r = Math.Max(r1, r2);
ElementPosition pos = new ElementPosition();
if (r == r1)
{
pos.Width = 100;
pos.Height = (float)(100*((maxY - minY) / r) / hei);
pos.X = 0;
pos.Y = (100 - pos.Height) / 2;
}
else
{
pos.Height = 100;
pos.Width = (float)(100 * ((maxX - minX) / r) / wid);
pos.Y = 0;
pos.X = (100 - pos.Width) / 2;
}
area.Position = pos;
}
}
7.FileHelper.cs
class FileHelper
{
public static List<string[]> OpenTxt(string filePath)
{
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
List<string[]> strings = new List<string[]>();
while(!sr.EndOfStream)
{
string[] buffer = sr.ReadLine().Split(new char[] { ',', ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
strings.Add(buffer);
}
fs.Close();
sr.Close();
return strings;
}
/// <summary>
/// 保存文本文件
/// </summary>
/// <param name="filepath">文件路径</param>
/// <param name="outString">输出文本字符</param>
public static void SaveTxt(string filepath, string outString)
{
StreamWriter sw = new StreamWriter(filepath);
sw.WriteLine(outString, true);
sw.Close();
}
/// <summary>
/// 保存Excel文件(com组件)
/// </summary>
/// <param name="dt">数据表</param>
/// <param name="filepath">文件路径</param>
public static void SaveXls(DataTable dt, string filepath)
{
Excel.Application excel = new Excel.Application();
excel.Visible = false;
excel.DisplayAlerts = false;
Excel.Workbook wb1 = excel.Workbooks.Add(System.Reflection.Missing.Value);
Excel.Worksheet ws1 = wb1.Worksheets.Add(System.Reflection.Missing.Value);
ws1.Name = dt.TableName;
int count_row = dt.Rows.Count;
int count_col = dt.Columns.Count;
Excel.Range range;
for (int i = 0; i < count_col; i++)
{//填充表头
ws1.Cells[1, i + 1] = dt.Columns[i].ColumnName;
range = (Excel.Range)ws1.Cells[1, i + 1];
range.Font.Name = "黑体";
range.Font.Size = 15;
range.Font.Color = ColorTranslator.ToOle(Color.White);//设置表头字体颜色
range.Font.Bold = true;
range.Interior.Color = ColorTranslator.ToOle(Color.Blue);//设置填充颜色
range.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;//设置居中水平
range.EntireColumn.AutoFit();
}
for (int i = 0; i < count_row; i++)
{
for (int j = 0; j < count_col; j++)
{
//按行填充
ws1.Cells[i + 2, j + 1] = dt.Rows[i][j];
range = (Excel.Range)ws1.Rows["2:" + (count_row + 1).ToString(), Type.Missing];
range.Font.Name = "黑体";
range.Font.Size = 12;
range.Font.Color = ColorTranslator.ToOle(Color.Black);//设置为黑色字体
range.Font.Bold = false;
range.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;//设置居中水平
range.EntireColumn.AutoFit();
}
}
wb1.SaveCopyAs(filepath);
wb1.Close();
excel.Quit();
}
}
8.MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
#region 变量区
public DataCenter data = new DataCenter();
#endregion
private void ClearData()
{
data = new DataCenter();
DrawChart.Series.Clear();
DataViewer.DataSource = null;
ReportBox.Clear();
}
//public void Refresh()
//{
// DataViewer.DataSource = data.PointToTable();
//}
private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "请选择需要处理的数据";
ofd.Filter = "文本文件|*.txt";
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
if (data.dataFlag)
{
ClearData();
}
List<string[]> strings = FileHelper.OpenTxt(ofd.FileName);
int tmpInd = 0;
for (int i = 0; i < strings.Count; i++)
{
string[] buffer = strings[i];
int n = buffer.Length;
if (n == 3)
{//起终点
Point tmp = new Point();
tmp.name = buffer[0];
tmp.X = Convert.ToDouble(buffer[1]);
tmp.Y = Convert.ToDouble(buffer[2]);
if (tmpInd == 0)
{
data.start = tmp;
data.start.LC_dobule = 0;//默认起点里程为0,若不为0,请自行修改代码
data.start.LC_string = HelpAlgorithm.LC2String(data.start.LC_dobule);//转为字符串型里程,存起来
tmpInd++;
}
else
{
data.end = tmp;
}
}
else if (n == 1 || n == 0)
{
continue;
}
else if (n == 5)
{
Point jd = new Point();
jd.name = buffer[0];
jd.X = Convert.ToDouble(buffer[1]);
jd.Y = Convert.ToDouble(buffer[2]);
double r = Convert.ToDouble(buffer[3]);
double ls = Convert.ToDouble(buffer[4]);
if (ls == 0)
{
jd.curveType = "YQX";
}
else jd.curveType = "HHQX";
Curve cv = new Curve();
cv.JD = jd;
cv.R = r;
cv.Ls = ls;
data.curves.Add(cv);
}
}
data.pile_Spacing = 10;// 默认桩距为10
CurrentPileSpacingBox.Clear();
CurrentPileSpacingBox.AppendText(data.pile_Spacing.ToString() + "m");//桩距显示在文本框中
MessageBox.Show("文件打开成功", "提示");
data.dataFlag = true;
}
catch
{
MessageBox.Show("文件格式不对,请重新打开", "提示");
}
}
}
/// <summary>
/// 窗口大小改变时保证chart的图像纵横比例不变
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if(DrawChart.Series.Count==2)
{
Draw.ControlScale(DrawChart.ChartAreas[0], DrawChart.Width, DrawChart.Height);
}
}
private void helpToolStripMenuItem_Click(object sender, EventArgs e)
{
string help = "导入数据后,点击计算即可";
MessageBox.Show(help, "帮助");
}
private void CurveCalToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void MileageToolStripMenuItem_Click(object sender, EventArgs e)
{
//if (data.dataMainPoint)
//{
// //计算里程桩坐标
// data.totalPoints = Algriothm.totalPoints(data.curves);
// data.dataMileage = true;
// data.dataMainPoint = false;
// lookImageToolStripMenuItem_Click(sender, e);
// Refresh();
// MessageBox.Show("里程桩计算完成", "提示");
//}
//else
//{
// MessageBox.Show("请先进行曲线要素计算", "提示");
//}
}
private void lookReportToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.calFlag)
{
ReportBox.Clear();
ReportBox.AppendText(data.GetReport());
PageController.SelectedIndex = 2;
MessageBox.Show("计算报告生成成功", "提示");
}
else
{
MessageBox.Show("请先进行计算", "提示");
}
}
private void lookImageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.calFlag )
{
Draw.DrawByChart(DrawChart, data.totalPoints);
PageController.SelectedIndex = 1;
MessageBox.Show("绘图完成", "提示");
}
else
{
MessageBox.Show("请先进行计算", "提示");
}
}
private void pToolStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
private void saveExcelToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.calFlag)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Excel文件|*.xls|所有文件|*.*";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
MessageBox.Show("此过程可能消耗一定时间,请耐心等待", "提示");
FileHelper.SaveXls(data.GetPointTable(),sfd.FileName);
MessageBox.Show("保存成功", "提示");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "保存失败");
}
}
}
else MessageBox.Show("请先完成计算", "提示");
}
private void functionToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.dataFlag)
{
Algorithm.PreProcess(ref data.curves, data.start, data.end);//预处理
for (int i = 0; i < data.curves.Count; i++)
{
//计算曲线要素
Curve tmpCV = data.curves[i];
Algorithm.CalCurveFeature(ref tmpCV);
}
Algorithm.CalJD_LC(ref data.curves, data.start, data.end);//计算交点里程
for (int i = 0; i < data.curves.Count; i++)
{
//计算曲线要素和主点坐标
Curve tmpCV = data.curves[i];
Algorithm.CalMainPoints(ref tmpCV);
}
data.totalPoints = Algorithm.CalIntegerPilePoints(ref data.curves, data.start, data.end, data.pile_Spacing);//得到所有的主点和整桩点
data.calFlag = true;
DataViewer.DataSource = data.GetPointTable();//将主点桩和整数桩信息输出到表格
PageController.SelectedIndex = 0;
MessageBox.Show("数据输出到表格完成", "提示");
lookImageToolStripMenuItem_Click(sender, e);//画图
lookReportToolStripMenuItem_Click(sender, e);//计算报告
}
else
{
MessageBox.Show("请先打开文件", "提示");
}
}
private void toolStripComboBox1_Click(object sender, EventArgs e)
{
}
private void fileToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void SetPileSpacingToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.dataFlag)
{
DialogResult dia = MessageBox.Show("默认桩间距为:" + data.pile_Spacing.ToString() + "m" + "\r\n" + "是否更改", "提示", MessageBoxButtons.OKCancel);
if (dia == DialogResult.OK)
{
SetPileSpacingForm newForm = new SetPileSpacingForm();
newForm.Owner = this;
newForm.ShowDialog();
CurrentPileSpacingBox.Clear();
CurrentPileSpacingBox.AppendText(data.pile_Spacing.ToString() + "m");
DialogResult dr = MessageBox.Show("当前基准高程为:" + data.pile_Spacing.ToString() + "m" + "\r\n" + "是否选择重新计算", "提示", MessageBoxButtons.OKCancel);
if (dr == DialogResult.OK)
{
data.calFlag = false;
functionToolStripMenuItem_Click(sender, e);
}else
{//重置为默认值
data.pile_Spacing = 10;
CurrentPileSpacingBox.Clear();
CurrentPileSpacingBox.AppendText(data.pile_Spacing.ToString() + "m");
MessageBox.Show("桩距重置为10m!");
functionToolStripMenuItem_Click(sender, e);
}
}
}
else MessageBox.Show("请先打开文件", "提示");
}
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.calFlag)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "jpg格式|*.jpg";
if (sfd.ShowDialog() == DialogResult.OK)
{
DrawChart.SaveImage(sfd.FileName, System.Windows.Forms.DataVisualization.Charting.ChartImageFormat.Jpeg);
MessageBox.Show("保存成功", "提示");
}
}
else MessageBox.Show("请先完成计算", "提示");
}
private void saveReportToolStripMenuItem_Click(object sender, EventArgs e)
{
if (data.calFlag)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "文本文件|*.txt|所有文件|*.*";
if (sfd.ShowDialog() == DialogResult.OK)
{
FileHelper.SaveTxt(sfd.FileName, ReportBox.Text);
MessageBox.Show("保存成功", "提示");
}
}
else MessageBox.Show("请先完成计算", "提示");
}
private void MainForm_Load(object sender, EventArgs e)
{
}
}
public partial class SetPileSpacingForm : Form
{
public SetPileSpacingForm()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
try
{
double newPileSpacing = double.Parse(EditBox.Text);
MainForm form = (MainForm)this.Owner;
form.data.pile_Spacing= newPileSpacing;
this.Close();
}
catch
{
MessageBox.Show("输入数据不合法", "提示");
}
finally
{
EditBox.Clear();
}
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void basiH_TextChanged(object sender, EventArgs e)
{
}
private void SetPileSpacingForm_Load(object sender, EventArgs e)
{
}
}