C# + Esri ArcGISRuntime WPF + 腾讯位置服务API实现路径规划(二)

        今天我们继续实现如何在地图上绘制得到的路径。在之前的文章中我们的程序使用了天地图作为底图 C# + Esri ArcGISRuntime WPF加载天地图_arcgis runtime api 天地图-CSDN博客

<esri:MapView x:Name="MapView" Margin="5" MouseDown="MapView_MouseDown"/>
private MapPoint ConvertMousePoint2MapPoint(System.Windows.Point windowsPoint)
{
    var point = MapView.ScreenToLocation(windowsPoint);
    return GeometryEngine.Project(point, SpatialReferences.Wgs84) as MapPoint;
}

 这里通过将屏幕点转换为坐标点,可以看到在地图点击事件(MouseDown)中拿到的坐标点(鼠标点中地图位置)为(4326)WGS84坐标系。

UI添加一个Button, 实现在地图点击选择起点、终点,计算路径。

private void RoutePlanClick(object sender, RoutedEventArgs e)
{
    graphicsOverlay.Graphics.Clear();
    Growl.Clear();
    Growl.Info("请选择起点");
    Array.Clear(routePlanPoints, 0, routePlanPoints.Length);

    currentEnumMapOperation = EnumMapOperation.AddRoutePlanFromPoint;
}

在地图MouseDown事件中,先暂时将起点、终点的位置存起来。通过枚举EnumMapOperation来定义当前地图点击事件执行哪个步骤,将点击的起点、终点暂时绘制到地图上(添加到GraphicsOverlay图层)。

private GraphicsOverlay graphicsOverlay;
private EnumMapOperation currentEnumMapOperation = EnumMapOperation.None;
private MapPoint[] routePlanPoints = new MapPoint[2];//存路径起点、终点

private SimpleMarkerSymbol startEndPointSymbol = new()
{
    Color = Color.FromArgb(255, 0, 0),
    Style = SimpleMarkerSymbolStyle.Circle,
    Size = 15d
};

private void MapView_MouseDown(object sender, MouseButtonEventArgs e)
{
    var mouseDownPoint = ConvertMousePoint2MapPoint(e.GetPosition(MapView));

    switch (currentEnumMapOperation)
    {
        case EnumMapOperation.AddRoutePlanFromPoint:
            {
                //存起点
                routePlanPoints[0] = mouseDownPoint;

                var point = new MapPoint(mouseDownPoint.X, mouseDownPoint.Y, SpatialReferences.Wgs84);
                //设置点样式并加到地图
                graphicsOverlay.Graphics.Add(new Graphic(point, startEndPointSymbol) { ZIndex = 99 });

                Growl.Clear();
                Growl.Info("请选择终点");
                currentEnumMapOperation = EnumMapOperation.AddRoutePlanToPoint;
            }
            break;
        case EnumMapOperation.AddRoutePlanToPoint:
            {
                //存终点
                routePlanPoints[1] = mouseDownPoint;

                var point = new MapPoint(mouseDownPoint.X, mouseDownPoint.Y, SpatialReferences.Wgs84);
                graphicsOverlay.Graphics.Add(new Graphic(point, startEndPointSymbol) { ZIndex = 99 });

                Growl.Clear();
                Growl.Info("开始计算绘制路径");
                currentEnumMapOperation = EnumMapOperation.None;

                _ = CalculateDrawRoutes();
            }
            break;
        case EnumMapOperation.None:
        default:
            break;
    }
}

private void InitBasemap()
{
    //加载天地图 矢量底图
    MapView.Map = new Map();
    var webtileBaseLayer = new WebTiledLayer(TianMapBaseMapUri);
    MapView.Map.Basemap?.BaseLayers.Add(webtileBaseLayer);

    //加载天地图 矢量注记
    var webtileNodeLayer = new WebTiledLayer(TianMapLabelUri);
    MapView.Map.OperationalLayers.Add(webtileNodeLayer);
    
    //设置地图初始位置
    MapView.SetViewpoint(new Viewpoint(
        latitude: 34.2784,
        longitude: 108.9414,
        scale: 120000));
    
    //添加图形临时图层
    graphicsOverlay = new GraphicsOverlay();
    MapView.GraphicsOverlays.Add(graphicsOverlay);
}


public enum EnumMapOperation
{
    None = 0,
    AddRoutePlanFromPoint = 1,
    AddRoutePlanToPoint = 2,
}

当选择完终点后,就可以调用Api来计算路径了。

private async Task CalculateDrawRoutes()
{
    //地图点击起点、终点 Wgs84转为Gcj02火星坐标系
    var convertStartPoint = CoordinateTransformation.Wgs84toGcj02(routePlanPoints[0].X, routePlanPoints[0].Y);
    var convertEndPoint = CoordinateTransformation.Wgs84toGcj02(routePlanPoints[1].X, routePlanPoints[1].Y);
    
    //调用腾讯API
    var routes = await HttpHelper.GetRouteByQQMapApi(convertStartPoint.lng, convertStartPoint.lat, convertEndPoint.lng, convertEndPoint.lat);
    var polylineCoords = routes.result?.routes.FirstOrDefault()?.polyline;
    if (polylineCoords == null)
    {
        Growl.Clear();
        Growl.Error("计算路径出错");
        graphicsOverlay.Graphics.Clear();
        return;
    }

    //解压路径坐标点
    CommonFunc.UnzipPolylineCoordsForQMap(polylineCoords);

    //构造点对象
    var routeCoords = CommonFunc.ConstructCoordsForQMapDrivingRoute(polylineCoords);

    //再将所有点从火星坐标系转回Wgs84
    var convertWgs84RouteCoords = new List<(double y, double x)>();
    foreach (var item in routeCoords)
    {
        var convertCoord = CoordinateTransformation.Gcj02toWgs84(item.x, item.y);
        convertWgs84RouteCoords.Add((convertCoord.lat, convertCoord.lng));
    }
    
    //绘制路径点到地图
    foreach (var coord in convertWgs84RouteCoords)
    {
        var point = new MapPoint(coord.x, coord.y, SpatialReferences.Wgs84);
        graphicsOverlay.Graphics.Add(new Graphic(point, routePointSymbol));
        await Task.Run(() => { Thread.Sleep(20); });
    }

    //将所有路径点拼成一整条完整路线并绘制
    //var pointLst = convertWgs84RouteCoords.Select(t => new MapPoint(t.x, t.y, SpatialReferences.Wgs84));
    //var polyLine = new Polyline(pointLst.ToArray(), SpatialReferences.Wgs84);
    //graphicsOverlay.Graphics.Add(new Graphic(polyLine, routeLineSymbol));
}

private SimpleMarkerSymbol routePointSymbol = new()
{
    Color = Color.FromArgb(1, 180, 115),
    Style = SimpleMarkerSymbolStyle.Circle,
    Size = 10d
};

private SimpleLineSymbol routeLineSymbol = new()
{
    Color = Color.FromArgb(1, 180, 115),
    Width = 10d,
    Style = SimpleLineSymbolStyle.Solid
};

最终效果是这样,每隔20毫秒绘制上一个路径点。 

(地图本身是很清晰的,转成gif就糊了...) 

 

这样路径虽然出来了,但由于是点,而不是线,所以看起来断断续续,效果不太好,再调整一下,将这部分代码放开,把所有路径点拼成一个完整路线绘制。

//将所有路径点拼成一整条完整路线并绘制
var pointLst = convertWgs84RouteCoords.Select(t => new MapPoint(t.x, t.y, SpatialReferences.Wgs84));
var polyLine = new Polyline(pointLst.ToArray(), SpatialReferences.Wgs84);
graphicsOverlay.Graphics.Add(new Graphic(polyLine, routeLineSymbol));

这样最终结果就是:

看起来舒服多了。ok,打完收工! 

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

biu啊biu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值