Show the route direction on a Gmap.Net.Winforms map middle route

149 Views Asked by At

I am using Gmap.Net.Winforms to show the routes existing in a list on the routes path in my winform project. I show the routes path correctly on the map, but now I want to show the direction path by an arrow on those routes path too. I don't know how may I show the path from first point to the next one correctly on the path. I think maybe I should use the angle between two points, but no idea how to use it.

for (int i = 1; i < mainPoints.Count; i++)
       {
           double lat = (mainPoints[i - 1].Lat + mainPoints[i].Lat) / 2;
           double lng = (mainPoints[i - 1].Lng + mainPoints[i].Lng) / 2;

           double xDiff = mainPoints[i-1].Lat + mainPoints[i].Lat;
           double yDiff = mainPoints[i-1].Lng + mainPoints[i].Lng;
           double degree = Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI;

           GMarkerCross cm = new GMarkerCross(new PointLatLng(lat, lng));
           cm.Pen = new Pen(System.Drawing.Color.Transparent);
                   
           cm.ToolTipText = ">";
 
           cm.ToolTip.Offset = new System.Drawing.Point(0, 0);
           cm.ToolTip.Font = new Font("Comic Sans MS", 25f, FontStyle.Bold | FontStyle.Italic);
           cm.ToolTip.Foreground = new SolidBrush(System.Drawing.Color.Red);
           cm.ToolTip.Fill = new SolidBrush(System.Drawing.Color.Transparent);
           cm.ToolTipMode = MarkerTooltipMode.Always;
           cm.ToolTip.Stroke = new Pen(System.Drawing.Color.Transparent);
           markersLayer.Markers.Add(cm);
         }

gmap.ZoomAndCenterRoute(route);
1

There are 1 best solutions below

5
On

First select a suitable shape for showing direction, preferably with transparent background: double arrow direction png image

Then put this shape as custom marker at the mid-points. The selected shape direction is toward up which means zero rotation needed when bearing is zero (i.e. toward north pole).

Calculate mid-points:

public const double k = Math.PI / 180d; // degrees to radians

public PointLatLng MidPoint(PointLatLng point1, PointLatLng point2)
{
    // Returns the half-way point along a great circle path between the two points.
    // https://www.movable-type.co.uk/scripts/latlong.html

    // Bx = cos φ2 ⋅ cos Δλ
    // By = cos φ2 ⋅ sin Δλ
    // φm = atan2(sin φ1 + sin φ2, √(cos φ1 + Bx)² +By² )
    // λm = λ1 + atan2(By, cos(φ1) + Bx)

    double φ1 = point1.Lat * k;
    double λ1 = point1.Lng * k;
    double φ2 = point2.Lat * k;
    double λ2 = point2.Lng * k;

    double Bx = Math.Cos(φ2) * Math.Cos(λ2 - λ1);
    double By = Math.Cos(φ2) * Math.Sin(λ2 - λ1);
    double φm = Math.Atan2(Math.Sin(φ1) + Math.Sin(φ2),
        Math.Sqrt(Math.Pow((Math.Cos(φ1) + Bx), 2d) + By * By));
    double λm = λ1 + Math.Atan2(By, Math.Cos(φ1) + Bx);
    return new PointLatLng(φm / k, λm / k);
}

Calculate Bearing:

public double Bearing(PointLatLng point1, PointLatLng point2)
{
    // returns bearing between to points in radians
    // https://www.movable-type.co.uk/scripts/latlong.html

    // θ = atan2(sin Δλ ⋅ cos φ2, cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ)

    double φ1 = point1.Lat * k;
    double λ1 = point1.Lng * k;
    double φ2 = point2.Lat * k;
    double λ2 = point2.Lng * k;
    double y = Math.Sin(λ2 - λ1) * Math.Cos(φ2);
    double x = Math.Cos(φ1) * Math.Sin(φ2) - Math.Sin(φ1) * Math.Cos(φ2) * Math.Cos(λ2 - λ1);
    return Math.Atan2(y, x);
}

Rotating Shape:

public Bitmap RotateShape(Bitmap shape, double angle) // angle in radians
{
    Bitmap bmp = new Bitmap(shape.Width, shape.Height);
    bmp.SetResolution(shape.HorizontalResolution, shape.VerticalResolution);
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.TranslateTransform(shape.Width / 2, shape.Height / 2);
        g.RotateTransform((float)(angle / k));
        g.TranslateTransform(-shape.Width / 2, -shape.Height / 2);
        g.DrawImage(shape, new Point(0, 0));
    }
    return bmp;
}

Sample Data:

PointLatLng[] coords = new PointLatLng[]
{
    new PointLatLng(22.314829392513598, 114.05459908390375),
    new PointLatLng(22.314861593596778, 114.05412482777214),
    new PointLatLng(22.314644236141167, 114.05375064403528),
    new PointLatLng(22.314535557286437, 114.05350263853526),
    new PointLatLng(22.313847255908490, 114.05338951321947),
    new PointLatLng(22.313706375091120, 114.05441199203533),
    new PointLatLng(22.313223354066515, 114.05435978035109),
    new PointLatLng(22.313162976320920, 114.05468610337743),
    new PointLatLng(22.313122724476038, 114.05478182479850),
    new PointLatLng(22.312893288738540, 114.05462083877217),
    new PointLatLng(22.312720205388830, 114.05442504495637),
    new PointLatLng(22.312893288738540, 114.05322852719314),
    new PointLatLng(22.313142850399935, 114.05328073887735)
};

Drawing the route with a direction inserted at mid-points of each segment and alignd to segment angle:

private void draw_path()
{
    gmap.MapProvider = GMapProviders.GoogleMap; ;
    GMaps.Instance.Mode = AccessMode.ServerOnly;

    GMapOverlay routeLayer = new GMapOverlay("routes");
    GMapRoute route = new GMapRoute(coords, string.Empty); 
    routeLayer.Routes.Add(route);
    gmap.Overlays.Add(routeLayer);

    GMapOverlay markersLayer = new GMapOverlay("markers");
    markersLayer.Id = "markers";

    GMarkerGoogle gm_start = new GMarkerGoogle(coords[0], GMarkerGoogleType.red);
    gm_start.ToolTipText = "Start";
    gm_start.ToolTipMode = MarkerTooltipMode.Always;
    markersLayer.Markers.Add(gm_start);
    
    GMarkerGoogle gm_end = new GMarkerGoogle(coords[coords.Length - 1], GMarkerGoogleType.red);
    gm_end.ToolTipText = "End";
    gm_end.ToolTipMode = MarkerTooltipMode.Always;
    markersLayer.Markers.Add(gm_end);

    for (int i = 1; i < coords.Length; i++)
    {
        using (Bitmap arrow = Resources.a1)
        {
            GMarkerGoogle gm = new GMarkerGoogle(
                p: MidPoint(coords[i - 1], coords[i]),
                bitmap: RotateShape(arrow, (float)(Bearing(coords[i - 1], coords[i])))
                );
            gm.Offset = new Point(-arrow.Width / 2, -arrow.Height / 2);
            markersLayer.Markers.Add(gm);
        }
    }

    gmap.Overlays.Add(markersLayer);
    gmap.ZoomAndCenterRoute(route);
}

Result: result

Zoomed View: zoomed view