上篇文章中我们实现了路径计算以及在地图上的绘制,今天我们继续实现模拟车辆行驶动态效果。主要涉及到车辆匀速行驶的轨迹点以及在每个位置车辆角度的计算。
先上效果视频:
首先从网上下载个导航箭头的图片,用来当做我们地图上导航前进的symbol。
其次呢,我们需要先把这段路径下,模拟车辆行驶的所有轨迹点先计算出来,在EsriArcGIS Sdk中提供了方法,可以返回Polyline指定距离的MapPoint:
public static MapPoint CreatePointAlong(this Polyline polyline, double distance);
因为CreatPointAlong中传入的Polyline必须是投影坐标系,但我们在上篇文章中C# + Esri ArcGISRuntime WPF + 腾讯位置服务API实现路径规划(二)-CSDN博客 从API中获取到的路径,以及绘制到地图上,都是地理坐标系经纬度的Geometry,所以此处还需要多一步坐标转换(地理转投影)。
从这个网站,我们查到了高斯-克吕格投影,西安的位置所处的带号大概是:
CGCS2000 / Gauss-Kruger zone 19 - EPSG:4497
Copy出Esri WKT
传入Polyline为总路径,vehicleSpeed = 16.666m/s假设车辆行驶速度为60km/h,计算出每秒车辆行驶的轨迹点。
public static List<MapPoint> GetUniformTrajectoryPoints(Polyline polyline, double vehicleSpeed = 16.666)
{
//CGCS2000 / Gauss-Kruger zone 19; 地理坐标系转为投影坐标系
var convertPolyline = GeometryEngine.Project(polyline, SpatialReference.Create("PROJCS[\"CGCS2000_GK_Zone_19\",GEOGCS[\"GCS_China_Geodetic_Coordinate_System_2000\",DATUM[\"D_China_2000\",SPHEROID[\"CGCS2000\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gauss_Kruger\"],PARAMETER[\"False_Easting\",19500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",111.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]")) as Polyline;
var resultPoints = new List<MapPoint>();
var allDistance = convertPolyline.Length();
var startIndex = 0;
double hasDrivenDistance;
while (true)
{
hasDrivenDistance = startIndex * vehicleSpeed;
if (hasDrivenDistance >= allDistance)
{
resultPoints.Add(convertPolyline.CreatePointAlong(allDistance));
break;
}
else
{
resultPoints.Add(convertPolyline.CreatePointAlong(hasDrivenDistance));
startIndex++;
}
}
return resultPoints;
}
定义导航图标的Symbol:
private PictureMarkerSymbol navigatorSymbol = new PictureMarkerSymbol(new RuntimeImage(File.ReadAllBytes(AppDomain.CurrentDomain.BaseDirectory + "\\Resource\\navigator.png")))
{
Height = 35,
Width = 35,
};
计算每两个轨迹点的弧度,以便导航图标的箭头角度可以与道路方向保持一致:
public static double CalculateAngle(Coordinate p0, Coordinate p1)
{
double x = p1.Y - p0.Y;
return Math.Atan2(p1.X - p0.X, x);
}
开始遍历每个轨迹点,绘制上图:
var allMovingPoints = CommonFunc.GetUniformTrajectoryPoints(polyLine);
for (int k = 0; k < allMovingPoints.Count; k++)
{
var currentPoint = allMovingPoints[k];
if (k + 1 < allMovingPoints.Count)
{
var nextPoint = allMovingPoints[k + 1];
//计算当前点与下一个点的夹角弧度
var angle = CommonFunc.CalculateAngle(new Coordinate
{
X = currentPoint.X,
Y = currentPoint.Y
}, new Coordinate
{
X = nextPoint.X,
Y = nextPoint.Y
});
//NTS package function: 弧度转角度
navigatorSymbol.Angle = AngleUtility.ToDegrees(angle);
//将该轨迹点添加symbol
var graphic = new Graphic(currentPoint, navigatorSymbol);
//置顶显示
graphic.ZIndex = 99;
graphic.Attributes.Add("Type", "Navigator");
//移除上一个旧的轨迹点,添加本次新的轨迹点
var tmpOldGraphic = graphicsOverlay.Graphics.FirstOrDefault(t => t.Attributes.ContainsKey("Type"));
graphicsOverlay.Graphics.Remove(tmpOldGraphic);
graphicsOverlay.Graphics.Add(graphic);
await Task.Run(() => { Thread.Sleep(10); });
}
}
OK,完成!