说明:利用Visio模具和具有站场基本信息的xml文件,生成点线拓扑,从而使用模具绘制完整的站场图
拓扑类
namespace InfoEdits
{
public class Point
{
public int ID { get; set; }//点id
public int TrackID { get; set; }//直股轨道编号
public int Track2ID { get; set; }//弯股轨道编号
public double X { get; set; }//X坐标
public double Y { get; set; }//Y坐标
public double KiloPos { get; set; }//公里标
public double Lat { get; set; }//纬度(数字度单位)
public double Lon { get; set; }//经度(数字度)
public double Hgt { get; set; }//高度(m)
public double DeltaPos { get; set; }//距离轨道起点的距离
public int ForwardID { get; set; } //前向指针(按照下行方向),虚拟终点的下行方向为999
public int ReverseID { get; set; }//后向指针(上行方向),虚拟起点的上行方向为999
public int SideID { get; set; } = 999;//侧向--主要针对道岔点的弯轨,无岔区段设置为999
public DeviceType pointType { get; set; } = DeviceType.PiecePoint;
public SwitchDirection SwitchDirection { get; set; } = SwitchDirection.None;//一般情况下点不为岔尖点
public string Tag { get; set; }//特殊备注,如道岔的编号
public int VisioIndex { get; set; }
public bool IsConnected { get; set; }
public Point()
{
}
public Point(double lat,double lon)
{
this.Lat = lat;
this.Lon = lon;
}
public Point(double lat, double lon,int ID)
{
this.Lat = lat;
this.Lon = lon;
this.ID = ID;
}
public Point(double lat, double lon, int ID,DeviceType type)
{
this.Lat = lat;
this.Lon = lon;
this.ID = ID;
this.pointType = type;
if(type==DeviceType.StartPoint)//如果是起点
{
this.ReverseID = 999;
this.ForwardID = ID + 1;
}
else if(type==DeviceType.EndPoint)//如果是终点
{
this.ReverseID = ID - 1;
this.ForwardID = 999;
}
else if(type == DeviceType.PiecePoint)
{
this.ReverseID = ID - 1;
this.ForwardID = ID + 1;
}
}
public Point(double lat, double lon, int ID,int TrackId, DeviceType type)
{
this.Lat = lat;
this.Lon = lon;
this.TrackID = TrackId;
this.Track2ID = TrackId;
this.ID = ID;
this.pointType = type;
if (type == DeviceType.StartPoint)//如果是起点
{
this.ReverseID = 999;
this.ForwardID = ID + 1;
}
else if (type == DeviceType.EndPoint)//如果是终点
{
this.ReverseID = ID - 1;
this.ForwardID = 999;
}
else if (type == DeviceType.PiecePoint)
{
this.ReverseID = ID - 1;
this.ForwardID = ID + 1;
}
}
public Point(double lat, double lon, int ID,int Trackid, DeviceType type, int reverseID, int forwardID)
{
this.Lat = lat;
this.Lon = lon;
this.TrackID = Trackid;
this.Track2ID = Trackid;
this.ID = ID;
this.pointType = type;
this.ReverseID = reverseID;
this.ForwardID = forwardID;
}
public Point(double lat, double lon, int ID, DeviceType type,int reverseID,int forwardID)
{
this.Lat = lat;
this.Lon = lon;
this.ID = ID;
this.pointType = type;
this.ReverseID = reverseID;
this.ForwardID = forwardID;
}
}
public class Line
{
public int ID { get; set; }
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public Line()
{ }
public Line(int ID)
{
this.ID = ID;
}
public Line(int ID,Point startPoint,Point endPoint)
{
this.ID = ID;
this.StartPoint = startPoint;
this.EndPoint = endPoint;
}
}
public class Track
{
public int ID { get; set; }
public double StartX { get; set; }//起始X坐标
public double StartY { get; set; }//起始Y坐标
public double EndX { get; set; }//结束X坐标
public double EndY { get; set; }//结束Y坐标
public double Y { get; set; } = 0.0;//直股的Y坐标
public double Deg { get; set; }//作为图元直线应该有deg弧度
public double Length { get; set; }//长度
public int[] inflectionPoints { get; set; } = new int[2];
public InfoEdits.Point[] InflectionPoints { get; set; }//侧线-的拐点
public List<Point> Points { get; set; }//点集
public List<Line> Lines { get; set; }//线集
public DeviceType Type { get; set; } = DeviceType.DownsideTrack;
/// <summary>
/// 找到侧线轨道的两个弯轨点
/// </summary>
/// <param name="Points"></param>
/// <returns></returns>
public void SetInflectionPoints()
{
if (this.Type == DeviceType.Side)
{
int[] flags = new int[2];
List<int> ff = new List<int>();
double temp = 0.0;
int tempid = 0;
for (int i = 1; i < Points.Count; i++)
{
double bear = GetBear(Points[i - 1].Lat, Points[i].Lat, Points[i - 1].Lon, Points[i].Lon);
Console.WriteLine(bear.ToString());
if (i == 1)
{
temp = bear;
tempid = Points[i].ID;
}
else if (Math.Abs(bear - temp) < 0.0174533)//设置阈值为1度
{
temp = bear;
}
else if (Math.Abs(bear - temp) > 0.0174533)//1度
{
temp = bear;
tempid = Points[i - 1].ID;
ff.Add(tempid);
}
Console.WriteLine(Math.Abs(bear - temp).ToString());
}
ff.Sort();
this.inflectionPoints[0] = ff[0];
this.inflectionPoints[1] = ff[1];
InfoEdits.Point[] pp = new InfoEdits.Point[2];
pp[0] = this.Points.Find(a => a.ID == ff[0]);
pp[1] = this.Points.Find(a => a.ID == ff[1]);
this.InflectionPoints = pp;
//this.CurvePoints[0] = this.Points.Find(a => a.ID == ff[0]);
//this.CurvePoints[1] = this.Points.Find(a => a.ID == ff[1]);
}
}
/// <summary>
/// 得到两点之间的航向角(弧度-3.14-3.14)
/// </summary>
/// <param name="LatA"></param>
/// <param name="LatB"></param>
/// <param name="LngA"></param>
/// <param name="LngB"></param>
/// <returns></returns>
private double GetBear(double LatA, double LatB, double LngA, double LngB)
{
double bear = 0.0;
//
double E = LngB - LngA;
double N = LatB - LatA;
bear = Math.Atan2(E, N);//得到弧度-3.14~3.14
return bear;
}
}
//public class TrackPiece
//{
// public int ID { get; set; }
// public int TrackID { get; set; }
// public int StartPointID { get; set; }
// public int EndPointID { get; set; }
// public double Bear { get; set; }
// public double Length { get; set; }
//}
public class Balise
{
public int ID { get; set; }
public double DeltaPos { get; set; }
public double X { get; set; }
public double Y { get; set; }
public int TrackID { get; set; }
public BaliseDirection Direction { get; set; } = BaliseDirection.temp;//预留
public BaliseProperty Property { get; set; } = BaliseProperty.temp;
public int Type { get; set; }
public int VisioIndex { get; set; }
}
public class Topology
{
public string Name { get; set; }//拓扑名称
public int ID { get; set; }//车站编号
public string UpLinkStationName { get; set; }
public string DownLinkStationName { get; set; }
public Direction Direction { get; set; } = 0;//初始设置为纬度升序
public List<Track> Tracks { get; set; }
public List<Point> Points { get; set; }
public List<Line> Lines { get; set; }
public List<Balise> Balises { get; set; }
public List<int> TrackID { get; set; }//正线ID
public List<int> CrossLineID { get; set; }//渡线ID
public List<int> SideID { get; set; }//侧线ID
public double Scale { get; set; } = 100;//比例尺,默认设置100
public Dictionary<int, InfoEdits.Point[]> Dic { get; set; } = new Dictionary<int, InfoEdits.Point[]>();//保存直线和正线的直线方程
/// <summary>
/// 更新Track上的点
/// </summary>
public void UpdateTrack()
{
List<InfoEdits.Point> points = this.Points;
foreach (InfoEdits.Track t in this.Tracks)
{
t.Points.ForEach
(
a => points.Find(b => b.ID == a.ID)
);
t.Y = t.Points.First().Y;
if (t.InflectionPoints != null)
{
t.InflectionPoints = new InfoEdits.Point[2] { t.Points.Find(b => b.ID == t.inflectionPoints[0]), t.Points.Find(b => b.ID == t.inflectionPoints[1]) };
t.Y = t.Points.Find(a => a.ID == t.inflectionPoints[0] + 1).Y;
}
}
}
public void UpdateLinearDic()
{
this.Dic.Clear();
foreach(Track t in this.Tracks)
{
if(t.Type==DeviceType.UpsideTrack||t.Type==DeviceType.DownsideTrack)
{
Dic.Add(t.ID, new Point[2] { t.Points.First(), t.Points.Last() });
}
else if(t.Type==DeviceType.Side)
{
if (!t.inflectionPoints.Contains(0))
{
Dic.Add(t.ID, t.InflectionPoints);
}
}
}
}
}
public enum DeviceType
{
PiecePoint=0,//轨道点
StartPoint=1,//虚拟起点
Signal=2,//信号机
Switch=3,//道岔
Crossline=4,//渡线
SingleTrack=5,//轨道区段
Side=6,//侧线
EndPoint=7,//虚拟终点
Balise=8,//应答器
UpsideTrack=9,
DownsideTrack=10
}
//按照正线的下行方向
public enum Direction
{
LatAscend=0,//纬度升序,站型1
LatDescend=1,//纬度降序,站型2
LngAscend =2,//经度升序,站型3
LngDesecnd =3,//经度降序,站型4
}
public enum SwitchDirection
{
Reverse=0,//岔尖所在轨道的位置偏移减小的方向(上行方向)
Forward = 1,//岔尖所在轨道的位置偏移增长方向(下行方向)
None=999//非道岔
}
public enum BaliseDirection
{
bothway=0,
reverse=1,
forward=2,
temp=3
}
public enum BaliseProperty
{
VB=0,//Virtual Balise
Entity=1,//实体应答器
VB_2=2,//有区间数据的虚拟应答器
temp=3//预留
}
}
思路见:
语雀内容
#region 列控数据表绘图方法
/// <summary>
/// 从列控工程数据表Excel表出图
/// </summary>
/// <param name="selectedFiles"></param>
private void DrawVisio(List<string> selectedFiles)
{
List<TxtPoint> allPoints = new List<TxtPoint>();
//利用循环遍历出key和value
//选择的文件---现在暂时必须只能是列控数据Excel表中的
foreach (string f in selectedFiles)
{
allPoints.AddRange((List<TxtPoint>)Hashtable[f]);
}
double minkilo = allPoints.Min(a => a.KiloPos);//最小公里标---定x轴
double maxkilo = allPoints.Max(a => a.KiloPos);//最大公里标
//之后考虑是否在Excel转Txtpoint的时候就提取轨道编号
//需要提取字符串中的数字
int trackidmin = allPoints.Min(a => ExtractNumbersFormString(a.TrackName));//最小的轨道编号-定y轴
int trackidmax = allPoints.Max(a => ExtractNumbersFormString(a.TrackName));//最大的轨道编号
//分类别保存
List<TxtPoint> joints = allPoints.Where(a => a.type == PointType.Joint).ToList();//绝缘节列表
List<TxtPoint> signals = allPoints.Where(a => a.type == PointType.Signal).ToList();//信号机列表
List<TxtPoint> ssignals = signals.Where(a => a.TypeName.Contains("S")).ToList();//上行信号机列表
List<TxtPoint> xsignals = signals.Where(a => a.TypeName.Contains("X")).ToList();//下行信号机列表
List<TxtPoint> switchs = allPoints.Where(a => a.type == PointType.Switch).ToList();//道岔列表
double deltakilo = maxkilo - minkilo;//主要为了和Page的宽度设置比例尺
int[] PosY = new int[] { 5, 6, 7, 8, 9, 10 };//直接定好根据轨道编号y坐标,索引值即轨道编号,即编号为1时y坐标为2
//公里标作为x坐标
//y坐标按照轨道编号来定
Visio.Shape shape;
//用轨道名称号重新分组
var group = joints.GroupBy(a => ExtractNumbersFormString(a.TrackName)).ToList();
foreach (IGrouping<int, TxtPoint> g in group)
{
List<int> shapeIndex = new List<int>();//每个组都有一个新的指数值表
List<TxtPoint> points = g.ToList();
points = points.OrderBy(a => a.KiloPos).ToList();//根据公里标重新排序
foreach (TxtPoint p in points)
{
int trackid = ExtractNumbersFormString(p.TrackName);
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Joint"], (p.KiloPos - minkilo) / deltakilo * 15, PosY[trackid]);
p.VisShapeIndex = shape.Index;//记住图形的index
}
for (int j = 0; j < points.Count - 1; j++)//连接每个shape
{
Visio.Page visPage = axDrawingControl1.Document.Pages[1];//ActivePage;
Shape BeginShape = visPage.Shapes[points[j].VisShapeIndex];
Shape EndShape = visPage.Shapes[points[j + 1].VisShapeIndex];
ConnectedShapes(BeginShape, EndShape);
points[j].IsConnected = true;
points[j + 1].IsConnected = true;
}
}
//用一个字典保存每个轨道的两个点
Dictionary<int, TxtPoint[]> dic = new Dictionary<int, TxtPoint[]>();
foreach (IGrouping<int, TxtPoint> g in group)
{
List<TxtPoint> points = g.ToList();
if (points.Count >= 2)
{
points = points.OrderBy(a => a.KiloPos).ToList();//根据公里标重新排序
TxtPoint[] p2 = new TxtPoint[2] { points[0], points[1] };//选取前两个
dic.Add(ExtractNumbersFormString(points[0].TrackName), p2);
}
}
//设置信号机的位置
//上行信号机在轨道的下方,所以y要减0.1左右
//同时还要考虑X/S信号机
foreach (TxtPoint p in ssignals)
{
int trackid = ExtractNumbersFormString(p.TypeName);
if (trackid == 0)//如果是S信号机
{
trackid = ReturnTrackId(p, dic);
}
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Signal2.0"], (p.KiloPos - minkilo) / deltakilo * 15, PosY[trackid] - 0.2);
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowTextXForm, 2).FormulaU = "Width*2";
shape.Characters.Begin = 0;
shape.Characters.End = 0;
shape.Characters.Text = p.TypeName;
p.VisShapeIndex = shape.Index;
}
foreach (TxtPoint p in xsignals)
{
int trackid = ExtractNumbersFormString(p.TypeName);
if (trackid == 0)//如果是X信号机
{
trackid = ReturnTrackId(p, dic);
}
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Signal1.0"], (p.KiloPos - minkilo) / deltakilo * 15, PosY[trackid] + 0.2);
//添加设备的名称/文本
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowTextXForm, 2).FormulaU = "Width*2";
shape.Characters.Begin = 0;
shape.Characters.End = 0;
shape.Characters.Text = p.TypeName;
p.VisShapeIndex = shape.Index;
}
//先设置Switch的位置,根据每个轨道两个点的直线来设置道岔的位置,并且保存Index值
List<int> switchIndex = new List<int>();
//将道岔按照公里标大小排序
switchs = switchs.OrderBy(a => a.KiloPos).ToList();
//比如江仓站就是13957;
foreach (TxtPoint p in switchs)
{
int trackid = ReturnTrackId(p, dic);//通过比较道岔点与轨道直线的距离判定属于哪个轨道
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Switch"], (p.KiloPos - minkilo) / deltakilo * 15, PosY[trackid]);
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowTextXForm, 2).FormulaU = "Width*5";
shape.Characters.Begin = 0;
shape.Characters.End = 0;
shape.Characters.Text = p.TypeName;
p.TrackName = trackid.ToString();
p.VisShapeIndex = shape.Index;
}
//连接各个Switch,思路是按照公里标相近的道岔,判断是否是同一个轨道---其实这样是不对的
//1-9,3-5
for (int i = 0; i < switchs.Count; i++)
{
if (!switchs[i].IsConnected)//如果图形没有连接过
{
Visio.Page visPage = axDrawingControl1.Document.Pages[1];//ActivePage
//当两个道岔轨道编号不等且时退出
for (int j = i; j < switchs.Count; j++)
{
int track1Id = Convert.ToInt32(switchs[i].TrackName);
int track2Id = Convert.ToInt32(switchs[j].TrackName);
int delta = Math.Abs(track1Id - track2Id);
//跳过轨道名称相同的和跳过不是相邻轨道的(差1)
if (delta == 0 || delta > 1)
{
continue;
}
//跳过已经连接了的轨道
if (switchs[j].IsConnected)
{
continue;
}
else if (!switchs[j].IsConnected)
{
Shape BeginShape = visPage.Shapes[switchs[i].VisShapeIndex];
Shape EndShape = visPage.Shapes[switchs[j].VisShapeIndex];
ConnectedShapes(BeginShape, EndShape);
switchs[i].IsConnected = true;
switchs[j].IsConnected = true;
break;
}
}
}
else
{
break;
}
}
}
#endregion
#region 电子地图xml文件绘制站场图
private void DrawTopology(Station station)
{
InfoEdits.Topology Topo = InitialTopoElements(station);//初始设置点线的连接关系
SetTrackX(ref Topo);//设置正线的X坐标
SetSwitchDirection(station, ref Topo);//设置道岔的开叉方向--以此为依据设置轨道的层数、Y坐标
Topo.UpdateTrack();//更新轨道的点
SetTrackY(ref Topo);//设置直股的Y坐标
//SetTrackY2(ref Topo);//设置直股的Y坐标
Topo.UpdateTrack();//更新Track中的点
SetAllCrossLineXY(ref Topo);//设置渡线的坐标;
//检查XY坐标
CheckXY(Topo.Points);
SetSideXY(ref Topo);//设置侧线的XY坐标
Topo.UpdateTrack();
//UpdateTrack(ref Topo);
SetBalisePos(ref Topo);//设置应答器的逻辑坐标
DrawTopology(ref Topo);
CheckXY(Topo.Points);
this.Topo = Topo;
}
/// <summary>
/// 初步建立拓扑点线连接图,点的编号和前后向类型
/// </summary>
/// <param name="station"></param>
private InfoEdits.Topology InitialTopoElements(Station station)
{
//初次添加轨道、点、线
InfoEdits.Topology topo = new InfoEdits.Topology();
topo.Name = station.StationProperties.StationName;
topo.UpLinkStationName = station.StationProperties.UplinkStationNum.ToString();
topo.DownLinkStationName = station.StationProperties.DownlinkStationNum.ToString();
List<InfoEdits.Track> tracks = new List<InfoEdits.Track>();
List<InfoEdits.Point> Points = new List<InfoEdits.Point>();
List<InfoEdits.Line> Lines = new List<InfoEdits.Line>();
int index = 1;
for (int i = 0; i < station.TrackInfo.Tracks.Count; i++)
{
Track tc = station.TrackInfo.Tracks[i];
InfoEdits.Track t = new InfoEdits.Track();
List<int> trackids = new List<int>();
List<int> CrosslineId = new List<int>();
List<int> SideId = new List<int>();
t.ID = tc.TrackID;
if(tc.TrackType == 1)
{
t.Type = InfoEdits.DeviceType.SingleTrack;
trackids.Add(t.ID);
}
else if(tc.TrackType==2)
{
t.Type = InfoEdits.DeviceType.UpsideTrack;
trackids.Add(t.ID);
}
else if (tc.TrackType == 3)
{
t.Type = InfoEdits.DeviceType.DownsideTrack;//正线轨道
trackids.Add(t.ID);
}
else if(tc.TrackType==4)
{
t.Type = InfoEdits.DeviceType.Side;//侧线
SideId.Add(t.ID);
}
else if(tc.TrackType==5)
{
t.Type = InfoEdits.DeviceType.Crossline;//渡线
CrosslineId.Add(t.ID);
}
topo.TrackID = trackids;
topo.SideID = SideId;
topo.CrossLineID = CrosslineId;
double startlat = tc.StartLat;
double startlon = tc.StartLon;
List<InfoEdits.Point> points = new List<InfoEdits.Point>();
List<InfoEdits.Line> lines = new List<InfoEdits.Line>();
if (tc.TrackType == 4 || tc.TrackType == 5)//如果是侧线或者是渡线,第一个point设置为Switch
{
//暂时ReverseID设置为0
int indexx = index;
InfoEdits.Point pp;
for (int j = 0; j < station.TrackInfo.TrackGIS.TrackPieceGIS[i].TrackPieces.Count; j++)
{
TrackPiece tp = station.TrackInfo.TrackGIS.TrackPieceGIS[i].TrackPieces[j];
if (j == 0)//是第一个点
{
pp=new InfoEdits.Point((tp.DeltaLat + startlat) / 3600000.0, (tp.DeltaLon + startlon) / 3600000.0, index, t.ID, InfoEdits.DeviceType.Switch);
points.Add(pp);
}
else
{
pp = new InfoEdits.Point((tp.DeltaLat + startlat) / 3600000.0, (tp.DeltaLon + startlon) / 3600000.0, index, t.ID, InfoEdits.DeviceType.PiecePoint);
points.Add(pp);
}
index++;
}
pp = new InfoEdits.Point(tc.EndLat / 3600000.0, tc.EndLon / 3600000.0, index, t.ID, InfoEdits.DeviceType.Switch, 0, index + 1);
points.Add(pp);
index++;
for (int j=indexx;j<index-1;j++)
{
lines.Add(new InfoEdits.Line(indexx, points.Find(a=>a.ID==indexx), points.Find(a => a.ID == indexx+1)));
}
}
else //如果是正线类型,设置起始点为StartPoint
{
int indexx = index;
InfoEdits.Point pp;
for (int j = 0; j < station.TrackInfo.TrackGIS.TrackPieceGIS[i].TrackPieces.Count; j++)
{
TrackPiece tp = station.TrackInfo.TrackGIS.TrackPieceGIS[i].TrackPieces[j];
if (j == 0)//是第一个点
{
pp = new InfoEdits.Point((tp.DeltaLat + startlat) / 3600000.0, (tp.DeltaLon + startlon) / 3600000.0, index, t.ID, InfoEdits.DeviceType.StartPoint);
points.Add(pp);
}
else
{
pp = new InfoEdits.Point((tp.DeltaLat + startlat) / 3600000.0, (tp.DeltaLon + startlon) / 3600000.0, index, t.ID, InfoEdits.DeviceType.PiecePoint);
points.Add(pp);
}
index++;
}
pp = new InfoEdits.Point(tc.EndLat / 3600000.0, tc.EndLon / 3600000.0, index, t.ID, InfoEdits.DeviceType.EndPoint);
points.Add(pp);
index++;
for (int j = indexx; j < index - 1; j++)
{
lines.Add(new InfoEdits.Line(indexx, points.Find(a => a.ID == indexx), points.Find(a => a.ID == indexx + 1)));
}
}
t.Points = points;
t.Lines = lines;
tracks.Add(t);
Points.AddRange(points);
Lines.AddRange(lines);
}
topo.Tracks = tracks;
topo.Points = Points;
topo.Lines = Lines;
if(tracks.First().StartX<tracks.Last().StartX)
{
topo.Direction = InfoEdits.Direction.LatAscend;
}
else
{
topo.Direction = InfoEdits.Direction.LatDescend;
}
topo.UpdateTrack();
foreach(InfoEdits.Track t in topo.Tracks)
{
t.SetInflectionPoints();//如果是侧线设置拐点
}
//设置道岔点的前向后向和侧向ID
//拓扑更新直线方程
topo.UpdateLinearDic();
var switchTracks = station.TrackInfo.Tracks.Where(a => a.TrackType > 3);//侧线和渡线
foreach (Track t in switchTracks)
{
var tt = tracks.Find(a => a.ID == t.TrackID);
SetSwitchPoint(ref tt, tracks,topo.Dic);
}
//检查--发现拓扑仍然不对
Check(topo);
//判断两个点之间是否有多余插入的点,重新排序。
//注意不仅点要排序,其实Line也要排序,其实line有重叠部分,在拓扑点安排好之前不应生成Line的编号
foreach(Track t in station.TrackInfo.Tracks)
{
if(t.TrackType<=3)
{
var group = topo.Points.GroupBy(a => a.TrackID == t.TrackID);
foreach (IGrouping<bool, InfoEdits.Point> g in group)
{
if (g.Key == true)
{
//直股编号上的所有点集合,重新排列前后顺序
List<InfoEdits.Point> points = (List<InfoEdits.Point>)g.ToList();
//首先根据纬度方向排序
//如果拓扑正线的方向是纬度升序
if (topo.Direction == InfoEdits.Direction.LatAscend|| topo.Direction == InfoEdits.Direction.LngDesecnd)
{
points = points.OrderBy(a => a.Lat).ToList();
for (int j = 0; j < points.Count; j++)
{
if (points[j].pointType == InfoEdits.DeviceType.StartPoint)
{
points[j].ForwardID = points[j + 1].ID;
}
else if (points[j].pointType == InfoEdits.DeviceType.EndPoint)
{
points[j].ReverseID = points[j - 1].ID;
}
else
{
points[j].ReverseID = points[j - 1].ID;
points[j].ForwardID = points[j + 1].ID;
}
}
}
//如果拓扑的方向是纬度降序
else if (topo.Direction == InfoEdits.Direction.LatDescend || topo.Direction == InfoEdits.Direction.LngAscend)
{
points = points.OrderByDescending(a => a.Lat).ToList();
for (int j = 0; j < points.Count; j++)
{
if (points[j].pointType == InfoEdits.DeviceType.StartPoint)
{
points[j].ForwardID = points[j + 1].ID;
}
else if (points[j].pointType == InfoEdits.DeviceType.EndPoint)
{
points[j].ReverseID = points[j - 1].ID;
}
else
{
points[j].ReverseID = points[j - 1].ID;
points[j].ForwardID = points[j + 1].ID;
}
}
}
}
}
}
}
topo.Balises = GetBalises(station);
//检查基本正确
return topo;
}
private List<InfoEdits.Balise> GetBalises(Station station)
{
List<Balise> balises = station.TrainControlData.BaliseData.Balises;
List<InfoEdits.Balise> bs = new List<InfoEdits.Balise>();
foreach(Balise b in balises)
{
InfoEdits.Balise b_2 = new InfoEdits.Balise();
b_2.ID = balises.IndexOf(b) + 1;
b_2.TrackID = b.BaliseTrackNum;
b_2.DeltaPos = b.BalisePos;
int direction = b.BaliseProperty & 192;
b_2.Direction = (InfoEdits.BaliseDirection)direction;
int prop = b.BaliseProperty & 3;
b_2.Property = (InfoEdits.BaliseProperty)prop;
b_2.Type = b.BaliseLoc;
bs.Add(b_2);
}
return bs;
}
/// <summary>
/// 更新Track上的点
/// </summary>
/// <param name="topo"></param>
private void UpdateTrack(ref InfoEdits.Topology topo)
{
List<InfoEdits.Point> points = topo.Points;
foreach(InfoEdits.Track t in topo.Tracks)
{
t.Points.ForEach
(
a => points.Find(b => b.ID == a.ID)
);
}
}
private string Check(InfoEdits.Topology topo)
{
string s = "";
foreach (InfoEdits.Track t in topo.Tracks)
{
s += t.ID.ToString() + "\r\n";
foreach (InfoEdits.Point p in t.Points)
{
s += string.Format("编号{0},前向点{1},后向点{2},侧边点{3},直股编号{4},弯股编号{5}", p.ID, p.ReverseID, p.ForwardID, p.SideID, p.TrackID, p.Track2ID) + "\r\n";
}
}
Console.WriteLine(s);
return s;
}
private string Check(List<InfoEdits.Point> points)
{
string s = "";
foreach (InfoEdits.Point p in points)
{
s += string.Format("编号{0},前向点{1},后向点{2},侧边点{3},直股编号{4},弯股编号{5}", p.ID, p.ReverseID, p.ForwardID, p.SideID, p.TrackID, p.Track2ID) + "\r\n";
}
Console.WriteLine(s);
return s;
}
/// <summary>
/// 检查点
/// </summary>
/// <param name="points"></param>
/// <returns></returns>
private string Check2(List<InfoEdits.Point> points)
{
string s = "";
foreach (InfoEdits.Point p in points)
{
s += string.Format("编号{0},道岔方向{1},点类型{2},备注{3}",p.ID, p.SwitchDirection,p.pointType.ToString(),p.Tag) + "\r\n";
}
Console.WriteLine(s);
return s;
}
///// <summary>
///// 设置道岔点的前后向节点指针
///// </summary>
///// <param name="track"></param>
///// <param name="tracks"></param>
///// <param name="dic"></param>
//private void SetSwitchPoint(ref InfoEdits.Track track,List<InfoEdits.Track> tracks,Dictionary<int,InfoEdits.Point[]> dic)
//{
// int tracknum = track.ID;//所处轨道的编号
// var startPoint = track.Points.First();
// var endPoint = track.Points.Last();
// if (startPoint.pointType == InfoEdits.DeviceType.Switch)
// {
// int trackID = ReturnTrackId(startPoint, dic);//dic中只保存正线直线方程
// InfoEdits.Track t = tracks.Find(a => a.ID == trackID);
// int[] ids = ReturnClosedID(startPoint, t.Points);
// startPoint.SideID = track.Points[1].ID;
// //dictionary保存的正线直线一定在道岔的两端,所以暂时不判断
// startPoint.ReverseID = ids[0];
// startPoint.ForwardID = ids[1];
// startPoint.TrackID = trackID;//直股ID
// }
// if (endPoint.pointType == InfoEdits.DeviceType.Switch)
// {
// int trackID = ReturnTrackId(endPoint, dic);//dic中只保存正线直线方程
// InfoEdits.Track t = tracks.Find(a => a.ID == trackID);
// int[] ids = ReturnClosedID(endPoint, t.Points);
// endPoint.SideID = track.Points.Last().ID - 1;//倒数第二个点的ID
// endPoint.ReverseID = ids[0];
// endPoint.ForwardID = ids[1];
// endPoint.TrackID = trackID;//直股ID
// }
//}
/// <summary>
/// 设置道岔点的前后向节点指针
/// </summary>
/// <param name="track"></param>
/// <param name="tracks"></param>
/// <param name="dic"></param>
private void SetSwitchPoint(ref InfoEdits.Track track, List<InfoEdits.Track> tracks, Dictionary<int, InfoEdits.Point[]> dic)
{
int tracknum = track.ID;//所处轨道的编号
var startPoint = track.Points.First();
var endPoint = track.Points.Last();
if (startPoint.pointType == InfoEdits.DeviceType.Switch)
{
int trackID = ReturnTrackId(startPoint, dic);//dic中只保存正线直线方程
startPoint.SideID = track.Points[1].ID;
//dictionary保存的正线直线一定在道岔的两端,所以暂时不判断
startPoint.TrackID = trackID;//直股ID
}
if (endPoint.pointType == InfoEdits.DeviceType.Switch)
{
int trackID = ReturnTrackId(endPoint, dic);//dic中只保存正线直线方程
endPoint.SideID = track.Points.Last().ID - 1;//倒数第二个点的ID
endPoint.TrackID = trackID;//直股ID
}
}
/// <summary>
/// 根据xml文件中的道岔设置相应的道岔点的开岔方向
/// </summary>
/// <param name="station"></param>
/// <param name="Topo"></param>
private void SetSwitchDirection(Station station,ref InfoEdits.Topology Topo)
{
var switchPoints = Topo.Points.Where(a=>a.pointType==InfoEdits.DeviceType.Switch).ToList();
List<Switch> switches = station.TrainControlData.SwitchData.Switches;
foreach(InfoEdits.Point p in switchPoints)
{
var switchs = switches.Where(a => a.SwitchPosTrackNum == p.TrackID&&a.SwitchReverseTrackNum == p.Track2ID);
foreach(Switch s in switchs)
{
if(Math.Abs(s.SwitchPos-p.X*10000)<=300)//阈值300cm-3m
{
p.Tag = "SW" + s.SwitchNum.ToString();
p.SwitchDirection = (InfoEdits.SwitchDirection)s.SwitchDirection;
}
}
}
//捡漏
var swip = switchPoints.FindAll(a => a.SwitchDirection == InfoEdits.SwitchDirection.None);
foreach(InfoEdits.Point p in swip)
{
var switchs = switches.Where(a => a.SwitchPosTrackNum == p.TrackID && a.SwitchReverseTrackNum == p.Track2ID);
foreach (Switch s in switchs)
{
if (Math.Round(s.SwitchPos/10000 - p.X,0) == -1)//阈值300cm-3m
{
p.Tag = "SW" + s.SwitchNum.ToString();
p.SwitchDirection = (InfoEdits.SwitchDirection)s.SwitchDirection;
}
}
}
Check2(switchPoints);
}
/// <summary>
/// 返回中心点与点集合距离的最小点,此方法针对已经确定centerP点处于正线的中间
/// </summary>
/// <param name="centerP">中心点</param>
/// <param name="points">要比较的点集</param>
/// <returns></returns>
private int[] ReturnClosedID(InfoEdits.Point centerP,List<InfoEdits.Point> points)
{
int[] ids = new int[2];
//points = points.OrderBy(a => a.Lat).ToList();//根据纬度排序
points = points.Where(a => a != centerP).ToList();//排除本身
Dictionary<int,double> dic = new Dictionary<int, double>();
List<double> distance = new List<double>();
foreach(InfoEdits.Point p in points)
{
double dis = GetDistance(centerP.Lat, centerP.Lon, p.Lat, p.Lon);
distance.Add(dis);
dic.Add(p.ID, dis);
}
distance =distance.OrderBy(a=>a).ToList();//按照距离升序排序。
var key1 = dic.Where(q => q.Value == distance[0]).Select(a => a.Key).ToList<int>();
var key2 = dic.Where(q => q.Value == distance[1]).Select(a => a.Key).ToList<int>();
if(key1[0]<key2[0])
{
ids[0] = key1[0];
ids[1] = key2[0];
}
else if(key1[0]>key2[0])
{
ids[0] = key2[0];
ids[1] = key1[0];
}
return ids;
}
/// <summary>
/// 根据直股上两点的距离设置相对位置X坐标
/// </summary>
/// <param name="topo"></param>
private void SetTrackX(ref InfoEdits.Topology topo)
{
//设置Y坐标,先找到正线
foreach (InfoEdits.Track t in topo.Tracks.FindAll(a => a.Type == InfoEdits.DeviceType.SingleTrack||a.Type==InfoEdits.DeviceType.DownsideTrack||a.Type==InfoEdits.DeviceType.UpsideTrack))
{
var points = topo.Points.FindAll(a => a.TrackID == t.ID);
//设置正线的x坐标;
double lat = 0.0;
double lng = 0.0;
if (topo.Direction == InfoEdits.Direction.LatDescend)
{
points = points.OrderByDescending(a => a.Lat).ToList();
lat = points.First().Lat;
lng = points.First().Lon;
}
else if (topo.Direction == InfoEdits.Direction.LatAscend)
{
points = points.OrderBy(a => a.Lat).ToList();
lat = points.First().Lat;
lng = points.First().Lon;
}
foreach (InfoEdits.Point p in points)
{
double length = GetDistance(lat, lng, p.Lat, p.Lon);
//p.X = length / 100;
p.X = length / topo.Scale;
}
}
}
/// <summary>
/// 根据道岔的开岔方向设置直股的Y坐标
/// </summary>
/// <param name="topo"></param>
private void SetTrackY(ref InfoEdits.Topology topo)
{
List<InfoEdits.Point> points = new List<InfoEdits.Point>();
List<InfoEdits.Point> switchs = new List<InfoEdits.Point>();
double[] PosY = new double[topo.Tracks.Count];
if (topo.Direction == InfoEdits.Direction.LatAscend)//纬度升序
{
switchs =topo.Points.FindAll(a => a.pointType == InfoEdits.DeviceType.Switch).OrderBy(a => a.Lat).ToList();
}
else if (topo.Direction == InfoEdits.Direction.LatDescend)//纬度降序
{
switchs = topo.Points.FindAll(a => a.pointType == InfoEdits.DeviceType.Switch).OrderByDescending(a => a.Lat).ToList();
}
PosY[0] = 5;//设置图纸上正线的Y坐标为5
//遍历正线和侧线轨道
//找到同属于一个所有道岔点,其中包括了弯轨是侧线或者渡线的道岔点
foreach (InfoEdits.Point p in switchs)
{
if (p.SwitchDirection == InfoEdits.SwitchDirection.Forward)//下行方向
{
//如果道岔点连接的是侧线,即单动道岔
InfoEdits.Track tc = topo.Tracks.Find(a => a.Points.Contains(p));
if (tc.Type == InfoEdits.DeviceType.Side)
{
if (PosY[p.TrackID - 1] != 0 && PosY[p.Track2ID - 1] == 0)//(PosY[t.ID - 1]!=0)
{
PosY[p.Track2ID - 1] = PosY[p.TrackID - 1] - 1;//PosY[t.ID - 1] - 1;//Y坐标-1
}
}
//如果道岔点连接的是渡线
else if (tc.Type == InfoEdits.DeviceType.Crossline)
{
int nextid = tc.Points.Last().TrackID;//渡线最后一个点
if (PosY[p.TrackID - 1] != 0&& PosY[nextid - 1]==0)//(PosY[t.ID - 1] != 0)
{
PosY[nextid - 1] = PosY[p.TrackID - 1] - 1;//PosY[t.ID - 1] - 1;//Y坐标-1
}
}
}
else if (p.SwitchDirection == InfoEdits.SwitchDirection.Reverse)//上行方向
{
//如果道岔点连接的是侧线,即单动道岔
InfoEdits.Track tc = topo.Tracks.Find(a => a.Points.Contains(p));
if (tc.Type == InfoEdits.DeviceType.Side)
{
if (PosY[p.TrackID - 1] != 0&& PosY[p.Track2ID - 1]==0) //(PosY[t.ID - 1] != 0)
{
PosY[p.Track2ID - 1] = PosY[p.TrackID - 1] + 1;//PosY[t.ID - 1] + 1;//Y坐标-1
}
}
//如果道岔点连接的是渡线
else if (tc.Type == InfoEdits.DeviceType.Crossline)
{
int nextid = tc.Points.Last().TrackID;
if (PosY[p.TrackID - 1] != 0&&PosY[nextid - 1] == 0)//(PosY[t.ID - 1] != 0)
{
PosY[nextid - 1] = PosY[p.TrackID - 1] + 1;//PosY[t.ID - 1] + 1;//Y坐标+1
}
}
}
}
foreach(double a in PosY)
{
int index = PosY.FindIndex(i=>i==a);
var track = topo.Tracks.Find(i => i.ID == index + 1);
track.Y = a;
}
//设置了正线和侧线直股的坐标即道岔点的Y坐标
foreach (InfoEdits.Track a in topo.Tracks)
{
if(a.Type == InfoEdits.DeviceType.SingleTrack || a.Type == InfoEdits.DeviceType.DownsideTrack || a.Type == InfoEdits.DeviceType.UpsideTrack)
{
var pps = topo.Points.FindAll(b => b.TrackID == a.ID);
foreach(InfoEdits.Point p in pps)
{
p.Y = PosY[a.ID - 1];
}
}
else if(a.Type==InfoEdits.DeviceType.Side)
{
var pps = topo.Points.FindAll(b => b.Track2ID == a.ID&&b.TrackID==b.Track2ID);
foreach (InfoEdits.Point p in pps)
{
p.Y = PosY[a.ID - 1];
}
}
}
CheckXY(topo.Points);
}
/// <summary>
/// 根据道岔的开岔方向设置直股的Y坐标
/// </summary>
/// <param name="topo"></param>
private void SetTrackY2(ref InfoEdits.Topology topo)
{
List<InfoEdits.Point> points = new List<InfoEdits.Point>();
List<InfoEdits.Point> switchs = new List<InfoEdits.Point>();
double[] PosY = new double[topo.Tracks.Count];
if (topo.Direction == InfoEdits.Direction.LatAscend)//纬度升序
{
switchs = topo.Points.FindAll(a => a.pointType == InfoEdits.DeviceType.Switch).OrderBy(a => a.Lat).ToList();
}
else if (topo.Direction == InfoEdits.Direction.LatDescend)//纬度降序
{
switchs = topo.Points.FindAll(a => a.pointType == InfoEdits.DeviceType.Switch).OrderByDescending(a => a.Lat).ToList();
}
PosY[0] = 5;//设置图纸上正线的Y坐标为5
//遍历正线和侧线轨道
//找到同属于一个所有道岔点,其中包括了弯轨是侧线或者渡线的道岔点
foreach (InfoEdits.Point p in switchs)
{
int track1id = p.TrackID;//直股id
InfoEdits.Point[] track1points = topo.Dic[track1id];
double angle1 = GetBear2(track1points[0].Lat, track1points[1].Lat, track1points[0].Lon, track1points[0].Lon);
InfoEdits.Point forwardPoint = topo.Points.Find(a => a.ID == p.SideID);
if (forwardPoint.ID < p.ID)//如果p点的侧边点编号比自己小,即p是股道的最后一个点,停止计算
{
continue;
}
double angle2 = GetBear2(p.Lat, forwardPoint.Lat, p.Lon, forwardPoint.Lon);
double delta = angle2 - angle1;//夹角
if (delta < 0)
{
InfoEdits.Track tc = topo.Tracks.Find(a => a.Points.Contains(p));
if(tc.Type==InfoEdits.DeviceType.Side)
{
int track2id = p.Track2ID;
PosY[track2id - 1] = PosY[track1id - 1] + 1;
}
else
{
int track2id = tc.Points.Last().TrackID;
PosY[track2id - 1] = PosY[track1id - 1] + 1;
}
}
else if (delta > 0)
{
InfoEdits.Track tc = topo.Tracks.Find(a => a.Points.Contains(p));
if (tc.Type == InfoEdits.DeviceType.Side)
{
int track2id = p.Track2ID;
PosY[track2id - 1] = PosY[track1id - 1] - 1;
}
else
{
int track2id = tc.Points.Last().TrackID;
PosY[track2id - 1] = PosY[track1id - 1] - 1;
}
}
}
foreach (double a in PosY)
{
int index = PosY.FindIndex(i => i == a);
var track = topo.Tracks.Find(i => i.ID == index + 1);
track.Y = a;
}
//设置了正线和侧线直股的坐标即道岔点的Y坐标
foreach (InfoEdits.Track a in topo.Tracks)
{
if (a.Type == InfoEdits.DeviceType.SingleTrack || a.Type == InfoEdits.DeviceType.DownsideTrack || a.Type == InfoEdits.DeviceType.UpsideTrack)
{
var pps = topo.Points.FindAll(b => b.TrackID == a.ID);
foreach (InfoEdits.Point p in pps)
{
p.Y = PosY[a.ID - 1];
}
}
else if (a.Type == InfoEdits.DeviceType.Side)
{
var pps = topo.Points.FindAll(b => b.Track2ID == a.ID && b.TrackID == b.Track2ID);
foreach (InfoEdits.Point p in pps)
{
p.Y = PosY[a.ID - 1];
}
}
}
CheckXY(topo.Points);
}
private void SetAllCrossLineXY(ref InfoEdits.Topology Topo)
{
var tracks = Topo.Tracks.FindAll(a => a.Type == InfoEdits.DeviceType.Crossline);
foreach(InfoEdits.Track t in tracks)
{
InfoEdits.Point[] PointAB = new InfoEdits.Point[2] { t.Points.First(), t.Points.Last() };
for (int i = 1; i < t.Points.Count - 1; i++)
{
var PointC = Topo.Points.Find(a=>a.ID==t.Points[i].ID);
double[] xy = PointBetweenPoints(PointC, PointAB);
PointC.X = xy[0];
PointC.Y = xy[1];
}
}
}
/// <summary>
/// 主要用来计算斜线上点的XY坐标
/// </summary>
/// <param name="PointC"></param>
/// <param name="Points">[0]-PointA;[1]-PointB</param>
/// <returns></returns>
private double[] PointBetweenPoints(InfoEdits.Point PointC,InfoEdits.Point[] Points)
{
double[] xy = new double[2];
InfoEdits.Point PointA = Points[0];
InfoEdits.Point PointB = Points[1];
double deltay = PointB.Y - PointA.Y;
double deltax = PointB.X - PointA.X;
double lengthAB = Math.Abs(GetDistance(PointA.Lat, PointA.Lon, PointB.Lat, PointB.Lon));
double lengthAC = Math.Abs(GetDistance(PointA.Lat, PointA.Lon, PointC.Lat, PointC.Lon));
xy[0] = lengthAC / lengthAB * deltax + PointA.X;
xy[1] = lengthAC / lengthAB * deltay + PointA.Y;
return xy;
}
//侧线上的所有Y已经设置好了
/// <summary>
/// 设置拓扑的侧线的所有点的坐标
/// </summary>
/// <param name="topo"></param>
private void SetSideXY(ref InfoEdits.Topology topo)
{
var side = topo.Tracks.FindAll(a => a.Type == InfoEdits.DeviceType.Side);
foreach (InfoEdits.Track t in side)
{
//获取侧线的两个折点
int[] curvedPoints = ReturnCurvedPoints(t.Points);
InfoEdits.Point A = t.Points.First();
InfoEdits.Point B = t.Points.Last();
//总长
double all = GetDistance(A.Lat, A.Lon, B.Lat, B.Lon);
double allxy = B.X - A.X;
var curvePoint1 = topo.Points.Find(a => a.ID == curvedPoints[0]);
var curvePoint2 = topo.Points.Find(a => a.ID == curvedPoints[1]);
//首先设置折点curvePoint1和curvePoint2的X坐标
//计算弧度
double d = GetDistance(A.Lat, A.Lon, curvePoint1.Lat, curvePoint1.Lon);
double angle = Math.Asin(GetPoint2Line(A, B, curvePoint1) / d);
curvePoint1.X = d * Math.Cos(angle)/topo.Scale+A.X;
d= GetDistance(B.Lat, B.Lon, curvePoint2.Lat, curvePoint2.Lon);
angle = Math.Asin(GetPoint2Line(A, B, curvePoint2) / d);
curvePoint2.X = B.X - d * Math.Cos(angle) / topo.Scale;
//分成三段处理
for (int j = 1; j < t.Points.IndexOf(curvePoint1); j++)
{
double[] PosXY = PointBetweenPoints(t.Points[j], new InfoEdits.Point[2] { A, curvePoint1 });
var point = topo.Points.Find(a => a.ID == t.Points[j].ID);
point.X = PosXY[0];
point.Y = PosXY[1];
}
//直股段
double dis = GetDistance(curvePoint1.Lat, curvePoint1.Lon, curvePoint2.Lat, curvePoint2.Lon);
double dx = curvePoint2.Y - curvePoint1.X;
for (int a = t.Points.IndexOf(curvePoint1) + 1; a < t.Points.IndexOf(curvePoint2); a++)
{
InfoEdits.Point PointA = t.Points[a - 1];
InfoEdits.Point PointB = t.Points[a];
double l = GetDistance(PointA.Lat, PointA.Lon, PointB.Lat, PointB.Lon);
var point = topo.Points.Find(b => b.ID == t.Points[a].ID);
//point.X = curvePoint1.X + l / dis * dx;
point.X = curvePoint1.X + l / Topo.Scale;
}
for (int b = t.Points.IndexOf(curvePoint2) + 1; b < t.Points.Count(); b++)
{
double[] PosXY = PointBetweenPoints(t.Points[b], new InfoEdits.Point[2] { curvePoint2, B });
var point = topo.Points.Find(a => a.ID == t.Points[b].ID);
point.X = PosXY[0];
point.Y = PosXY[1];
}
}
}
private void SetBalisePos(ref InfoEdits.Topology topo)
{
foreach(InfoEdits.Balise b in topo.Balises)
{
var t = topo.Tracks.Find(a => a.ID == b.TrackID);
double startx = t.Points.First().X;
double y = t.Y;
if (t.Type==InfoEdits.DeviceType.UpsideTrack|| t.Type == InfoEdits.DeviceType.DownsideTrack|| t.Type == InfoEdits.DeviceType.SingleTrack)
{
b.X = startx + b.DeltaPos / 100 / topo.Scale;
b.Y = y - 0.1;
}
else if(t.Type==InfoEdits.DeviceType.Side)
{
InfoEdits.Point inflectionPoint1 = t.InflectionPoints[0];
var basex = topo.Tracks.Find(a => a.Type == InfoEdits.DeviceType.DownsideTrack).Points.First().X;
b.X = b.DeltaPos/100/topo.Scale+basex;
b.Y = y - 0.1;
}
}
}
/// <summary>
/// 绘制已经编制好的Topo至Visio图纸
/// </summary>
/// <param name="topo"></param>
private void DrawTopology(ref InfoEdits.Topology topo)
{
SetPointPos(ref topo);//设置所有点(未包括信号机、应答器)
ConnectAllPoints(topo);
SetOthersShape(topo);//设置下行方向,上行车站、下行车站等形状
//SetBalisePos(ref topo);
SetBaliseShape(ref topo);
}
private void ConnectAllPoints(InfoEdits.Topology topo)
{
foreach (InfoEdits.Track t in topo.Tracks)
{
if (t.Type == InfoEdits.DeviceType.SingleTrack || t.Type == InfoEdits.DeviceType.DownsideTrack || t.Type == InfoEdits.DeviceType.UpsideTrack)
{
var points = topo.Points.FindAll(a => a.TrackID == t.ID);
ConnectPoints(points);
}
else
{
var points = topo.Points.FindAll(a => a.Track2ID == t.ID);
ConnectPoints(points);
}
}
}
/// <summary>
/// 遍历拓扑中的所有点并设置XY坐标,记录point的VisioIndex
/// </summary>
/// <param name="topo"></param>
private void SetPointPos(ref InfoEdits.Topology topo)
{
Shape shape;
foreach (InfoEdits.Point p in topo.Points)
{
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Joint"], p.X, p.Y);
p.VisioIndex = shape.Index;//记住图形的index
shape.Characters.Begin = 0;
shape.Characters.End = 0;
if (string.IsNullOrEmpty(p.Tag))
{
shape.Characters.Text = p.ID.ToString();
}
else
{
shape.Characters.Text = p.Tag;
}
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndices.visRowTextXForm, 6).FormulaU = "90 deg";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndices.visRowTextXForm, 2).FormulaU = "Width*10";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndices.visRowTextXForm, 0).FormulaU = "Width*-0.8";
}
}
/// <summary>
/// 连接两个Visio绝缘节对象
/// </summary>
/// <param name="points"></param>
private void ConnectPoints(List<InfoEdits.Point> points)
{
for (int j = 0; j < points.Count - 1; j++)
{
Visio.Page visPage = axDrawingControl1.Document.Pages[1];//ActivePage;
Shape BeginShape = visPage.Shapes[points[j].VisioIndex];
Shape EndShape = visPage.Shapes[points[j + 1].VisioIndex];
ConnectedShapes(BeginShape, EndShape);
points[j].IsConnected = true;
points[j + 1].IsConnected = true;
}
}
private void SetBaliseShape(ref InfoEdits.Topology topo)
{
Shape shape;
foreach(InfoEdits.Balise b in topo.Balises)
{
string shapename = string.Format("Balise{0}", b.Type);
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters[shapename],b.X, b.Y);
b.VisioIndex = shape.Index;
}
}
private void SetOthersShape(InfoEdits.Topology topo)
{
double minx = topo.Points.Min(a => a.X);
double maxx = topo.Points.Max(a => a.X);
double maxy = topo.Points.Max(a => a.Y);
double width = 2;
double height = 0.4;
double deltay = 2;//Y坐标偏移
double deltax = 0.8;
//添加下行方向标志
Shape shape;
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Direction"], (minx+maxx)/2, maxy+1);
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndices.visRowXForm1D, 2).FormulaU = "334.30000280175 mm";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject,
(short)VisRowIndices.visRowXForm1D, 3).FormulaU = "177.00000147154 mm";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowLine, 0).FormulaU = "2 pt";
shape.Characters.CharProps[7] = 30;
//添加车站文本,设置无外框线
shape = axDrawingControl1.Document.Pages[1].DrawRectangle((minx + maxx) / 2 - width / 2+deltax, maxy+height/2+deltay, (minx + maxx) / 2 + width / 2+deltax, maxy - height/2+deltay);
shape.TextStyle = "Normal";
shape.LineStyle = "Text Only";
shape.FillStyle = "Text Only";
shape.Characters.Begin = 0;
shape.Characters.End = 0;
shape.Characters.Text = topo.Name;
shape.get_CellsSRC((short)VisSectionIndices.visSectionCharacter, 0, 7).FormulaU = "30 pt";
shape.get_CellsSRC((short)VisSectionIndices.visSectionCharacter, 0, 2).FormulaU = "17";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowLine, 2).FormulaU = "0";
shape.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowGradientProperties, 4).FormulaU = "FALSE";
}
/// <summary>
/// 得到两点之间的航向角(弧度-3.14-3.14)
/// </summary>
/// <param name="LatA"></param>
/// <param name="LatB"></param>
/// <param name="LngA"></param>
/// <param name="LngB"></param>
/// <returns></returns>
private double GetBear(double LatA, double LatB, double LngA, double LngB)
{
double bear = 0.0;
//
double E = LngB - LngA;
double N = LatB - LatA;
bear = Math.Atan2(E, N);//得到弧度-3.14~3.14
return bear;
}
/// <summary>
/// 找到侧线轨道的两个弯轨点
/// </summary>
/// <param name="Points"></param>
/// <returns></returns>
private int[] ReturnCurvedPoints(List<InfoEdits.Point> Points)
{
int[] flags = new int[2];
List<int> ff = new List<int>();
double temp = 0.0;
int tempid = 0;
for (int i = 1; i < Points.Count; i++)
{
double bear = GetBear(Points[i - 1].Lat, Points[i].Lat, Points[i - 1].Lon, Points[i].Lon);
Console.WriteLine(bear.ToString());
if (i == 1 )
{
temp = bear;
tempid = Points[i].ID;
}
else if (Math.Abs(bear - temp) < 0.0174533)//设置阈值为1度
{
temp = bear;
}
else if (Math.Abs(bear - temp) > 0.0174533)//1度
{
temp = bear;
tempid = Points[i - 1].ID;
ff.Add(tempid);
}
Console.WriteLine(Math.Abs(bear - temp).ToString());
}
ff.Sort();
flags[0] = ff[0];
flags[1] = ff[1];
Console.WriteLine(flags[0].ToString()+","+flags[1].ToString());
return flags;
}
/// <summary>
/// 检查点坐标
/// </summary>
/// <param name="points"></param>
private void CheckXY(List<InfoEdits.Point> points)
{
string s = "";
foreach(InfoEdits.Point p in points)
{
s += string.Format("ID{0},X坐标{1},Y坐标{2}",p.ID, p.X, p.Y) + "\r\n";
}
Console.WriteLine(s);
}
private void DrawTopo(InfoEdits.Topology topo)
{
foreach(InfoEdits.Track t in topo.Tracks)
{
var points = topo.Points.FindAll(a => a.TrackID == t.ID);
if(t.Type == InfoEdits.DeviceType.SingleTrack || t.Type == InfoEdits.DeviceType.DownsideTrack || t.Type == InfoEdits.DeviceType.UpsideTrack)
{
double lat = 0.0;
double lng = 0.0;
if(topo.Direction==InfoEdits.Direction.LatDescend)
{
points = points.OrderByDescending(a => a.Lat).ToList();
lat = points.First().Lat;
lng = points.First().Lon;
}
else if(topo.Direction == InfoEdits.Direction.LatAscend)
{
points = points.OrderBy(a => a.Lat).ToList();
lat = points.First().Lat;
lng = points.First().Lon;
}
Shape shape;
foreach (InfoEdits.Point p in points)
{
double length = GetDistance(lat, lng, p.Lat, p.Lon);
p.X = length / 100;
p.Y = p.TrackID;
shape = axDrawingControl1.Document.Pages[1].Drop(currentStencil.Masters["Joint"], p.X, p.Y);
p.VisioIndex = shape.Index;//记住图形的index
}
for (int j = 0; j < points.Count - 1; j++)//连接每个shape
{
Visio.Page visPage = axDrawingControl1.Document.Pages[1];//ActivePage;
Shape BeginShape = visPage.Shapes[points[j].VisioIndex];
Shape EndShape = visPage.Shapes[points[j + 1].VisioIndex];
ConnectedShapes(BeginShape, EndShape);
BeginShape.Characters.Begin = 0;
BeginShape.Characters.End = 0;
BeginShape.Characters.Text = points[j].ID.ToString();
EndShape.Characters.Begin = 0;
EndShape.Characters.End = 0;
EndShape.Characters.Text = points[j + 1].ID.ToString();
points[j].IsConnected = true;
points[j + 1].IsConnected = true;
}
}
}
}
/// <summary>
/// 以中心点旋转Angle角度
/// </summary>
/// <param name="center">中心点</param>
/// <param name="p1">待旋转的点</param>
/// <param name="angle">旋转角度(弧度)</param>
private void PointRotate(Point center, ref Point p1, double angle)
{
double x1 = (p1.X - center.X) * Math.Cos(angle) + (p1.Y - center.Y) * Math.Sin(angle) + center.X;
double y1 = -(p1.X - center.X) * Math.Sin(angle) + (p1.Y - center.Y) * Math.Cos(angle) + center.Y;
p1.X = (int)x1;
p1.Y = (int)y1;
}
/// <summary>
/// 以中心点旋转Angle角度
/// </summary>
/// <param name="centerX"></param>
/// <param name="centerY"></param>
/// <param name="pointX"></param>
/// <param name="pointY"></param>
/// <param name="angle"></param>
private void PointRotate(double centerX,double centerY,ref double pointX,ref double pointY, double angle)
{
double x1 = (pointX - centerX) * Math.Cos(angle) + (pointY - centerY) * Math.Sin(angle) + centerX;
double y1 = -(pointX - centerX) * Math.Sin(angle) + (pointY - centerY) * Math.Cos(angle) + centerY;
pointX = x1;
pointY = y1;
}
private double GetBear2(double LatA, double LatB, double LngA, double LngB)
{
double bear = 0.0;
//
double E = LngB - LngA;
double N = LatB - LatA;
bear = Math.Atan2(E, N);//得到弧度-3.14~3.14
if (bear < 0)
{
bear += 6.28;//弧度范围0~6.28
}
//改成角度
//bear=headingA*180/Math.PI;
//if(bear<0)
//{
// bear += 360;//
//}
////方位角转换转弧度
//bear *= 0.0174533;
//if(bear>3.14)
//{
// bear -= 6.28;
//}
return bear;
}
public int ExtractNumbersFormString(string s)
{
//取出字符串中所有的英文字母
string strSplit1 = Regex.Replace(s, "[a-z]", "", RegexOptions.IgnoreCase);
////取出字符串中所有的数字
//string strSplit2 = Regex.Replace(FlightNO, "[0-9]", "", RegexOptions.IgnoreCase);
if (string.IsNullOrEmpty(strSplit1))//避免S/X这种情况,
{
return 0;
}
else
{
return Convert.ToInt32(strSplit1);
}
}
/// <summary>
/// 连接绝缘节
/// </summary>
/// <param name="BeginShape"></param>
/// <param name="EndShape"></param>
private void ConnectedShapes(Shape BeginShape,Shape EndShape)
{
Visio.Cell BeginXCell;
Visio.Cell EndXCell;//用来确定连接线连在图形的上下左右,不同图形值不一样
Page visPage = axDrawingControl1.Document.Pages[1];
Shape connector = visPage.Drop(visApp.ConnectorToolDataObject, 1.2386, 3.2458);
BeginXCell = connector.get_CellsU("BeginX");
EndXCell = BeginShape.get_CellsSRC(7, 0, 0);
BeginXCell.GlueTo(EndXCell);
BeginXCell = connector.get_CellsU("EndX");
EndXCell = EndShape.get_CellsSRC(7, 0, 0);
BeginXCell.GlueTo(EndXCell);
}
/// <summary>
/// 点P到直线AB的距离,P为线外一点,AB为线段两个端点
/// </summary>
/// <param name="pointA"></param>
/// <param name="pointB"></param>
/// <param name="P"></param>
/// <returns></returns>
private double GetPoint2Line(TxtPoint pointA,TxtPoint pointB, TxtPoint pointP)
{
//P为线外一点,AB为线段两个端点
//求直线方程
double A = 0, B = 0, C = 0;
A = pointA.Longtitude/3600000.0 - pointB.Longtitude/3600000.0;
B = pointB.Latitude/3600000 - pointA.Latitude/3600000;
C = pointA.Latitude/3600000 * pointB.Longtitude/3600000 - pointA.Longtitude/3600000 * pointB.Latitude/3600000;
//代入点到直线距离公式
double distance = 0;
distance = (Math.Abs(A * pointP.Latitude/3600000 + B * pointP.Longtitude/3600000 + C)) / (Math.Sqrt(A * A + B * B));
return distance;
}
private double GetPoint2Line(InfoEdits.Point pointA, InfoEdits.Point pointB, InfoEdits.Point pointP)
{
//P为线外一点,AB为线段两个端点
//求直线方程
double A = 0, B = 0, C = 0;
A = pointA.Lon - pointB.Lon;
B = pointB.Lat - pointA.Lat;
C = pointA.Lat * pointB.Lon - pointA.Lon * pointB.Lat;
//代入点到直线距离公式
double distance = 0;
distance = (Math.Abs(A * pointP.Lat + B * pointP.Lon + C)) / (Math.Sqrt(A * A + B * B));
if (!double.IsNaN(distance))
{
return distance;
}
else
{
return 0;
}
}
private int ReturnTrackId(TxtPoint switchPoint,Dictionary<int,TxtPoint[]> dic)
{
int trackid = 0;
Dictionary<int,double> distance = new Dictionary<int, double>();
foreach(KeyValuePair<int,TxtPoint[]> pair in dic)
{
int key = pair.Key;
distance.Add(key,(GetPoint2Line(dic[key][0], dic[key][1], switchPoint)));
}
var mindis = distance.Values.Min();
trackid = distance.First(a => a.Value == mindis).Key;
return trackid;
}
/// <summary>
/// 通过比较直线外点和直线的距离判断属于哪个轨道
/// </summary>
/// <param name="pointP"></param>
/// <param name="dic">int 轨道编号,Point[] 轨道的两个端点</param>
/// <returns></returns>
private int ReturnTrackId(InfoEdits.Point pointP, Dictionary<int, InfoEdits.Point[]> dic)
{
int trackid = 0;
Dictionary<int, double> distance = new Dictionary<int, double>();
foreach (KeyValuePair<int, InfoEdits.Point[]> pair in dic)
{
int key = pair.Key;
distance.Add(key, (GetPoint2Line(dic[key][0], dic[key][1], pointP)));
}
var mindis = distance.Values.Min();
trackid = distance.First(a => a.Value == mindis).Key;
return trackid;
}
/***** 点到直线的距离:P到AB的距离*****/
//P为线外一点,AB为线段两个端点
float getDist_P2L(Point pointP, Point pointA, Point pointB)
{
//求直线方程
int A = 0, B = 0, C = 0;
A = pointA.Y - pointB.Y;
B = pointB.X - pointA.X;
C = pointA.X * pointB.Y - pointA.Y * pointB.X;
//代入点到直线距离公式
float distance = 0;
distance = ((float)Math.Abs(A * pointP.X + B * pointP.Y + C)) / ((float)Math.Sqrt(A * A + B * B));
return distance;
}
#endregion