2

I am using Gmap.net API for a small vehicle tracking project. This project is in windows form c#. I am getting info from device like: Latitude, Longitude, Speed, Heading and some other information as well. The Heading information is in degree (0~359), How i can show that the vehicle is moving in some direction with an arrow sign?

  • Make a long isosceles triangle and rotate in direction vehicle is moving. Maybe one of the triangles on following page will help : https://www.google.com/search?q=types+of+triangles&espv=2&biw=1680&bih=944&tbm=isch&tbo=u&source=univ&sa=X&sqi=2&ved=0ahUKEwjHh4Tnr7nPAhWCKyYKHUqNAcsQsAQIGw – jdweng Oct 01 '16 at 10:17

2 Answers2

2

I know this thread is almost a year old but this is how I create a boat marker I rotate based on the orientation of the boat. I also draw the boat differently based on the zoom level.

Sorry for the lack of comments!

Namespace GMap.NET.WindowsForms.Markers

Public Class GMapMarkerBoat
    Inherits GMapMarker
    Public Brush As Brush
    Public boatHeading As Double

    Public Sub New(ic As SEAS_DATA.ImageCluster, b As Brush)
        MyBase.New(ic.LatLong)
        boatHeading = ic.IMU_Heading

        Brush = b

        'Size of the marker
        Size = New Size(8, 8)

    End Sub

    Public Overrides Sub OnRender(g As Graphics)

        Dim newSize As Size
        Dim maxZoomLevel As Integer = SEAS_Forms.frmMain.myMap.MaxZoom

        Select Case SEAS_Forms.frmMain.myMap.Zoom
            Case maxZoomLevel
                newSize = New Size(Size.Width * 2, Size.Height * 2)
            Case maxZoomLevel - 1 To maxZoomLevel
                newSize = New Size(CInt(Size.Width * 1.5), CInt(Size.Height * 1.5))
            Case maxZoomLevel - 2 To maxZoomLevel - 1
                newSize = Size
            Case SEAS_Forms.frmMain.myMap.MinZoom To maxZoomLevel - 2
                newSize = New Size(CInt(Size.Width / 2), CInt(Size.Height / 2))
        End Select

        'boat
        Dim boat(4) As PointF

        boat(0).X = CSng(-newSize.Width / 2)
        boat(0).Y = CSng(-newSize.Height / 2)
        boat(1).X = (boat(0).X + newSize.Width)
        boat(1).Y = boat(0).Y
        boat(3).X = boat(0).X
        boat(3).Y = (boat(0).Y + newSize.Height)
        boat(2).X = boat(1).X
        boat(2).Y = boat(3).Y
        boat(4).X = CSng(boat(0).X - newSize.Width / 2)
        boat(4).Y = CSng(boat(0).Y + newSize.Width / 2)

        If SEAS_Forms.frmMain.myMap.Zoom > maxZoomLevel - 4 Then
            boat = TransformAndRotate(boatHeading, boat) 'simplified rotation and transformation matrix
        Else
            boat = TransformAndRotate(0, boat)
        End If

        'start drawing here
        Select Case SEAS_Forms.frmMain.myMap.Zoom
            Case maxZoomLevel - 3 To maxZoomLevel
                g.FillPolygon(Brush, boat)
            Case SEAS_Forms.frmMain.myMap.MinZoom To maxZoomLevel - 3
                Dim newRect As New RectangleF(boat(0).X, boat(0).Y, newSize.Width, newSize.Height)
                g.FillEllipse(Brush, newRect)
        End Select

    End Sub

    Private Function TransformAndRotate(heading As Double, points() As PointF) As PointF()

        Dim cosRot As Double = Math.Cos((heading + 90) * Math.PI / 180)
        Dim sinRot As Double = Math.Sin((heading + 90) * Math.PI / 180)

        For i = 0 To points.Length - 1
            Dim x As Single = points(i).X
            Dim y As Single = points(i).Y
            points(i).X = CSng((LocalPosition.X) + (x * cosRot - y * sinRot)) 'simplified rotation and transformation matrix
            points(i).Y = CSng((LocalPosition.Y) + (x * sinRot + y * cosRot))
        Next

        Return points
    End Function

End Class

End Namespace

The custom class object I'm passing in (ic As ImageCluster) has the properties for the PointLatLng and the heading.

Here is how I add the marker

'add the marker to the overlay
newOverlay.Markers.Add(New GMap.NET.WindowsForms.Markers.GMapMarkerBoat(ic, Brushes.Red))
Kent
  • 21
  • 2
0

This is not quite as trivial as it seems. One option is to simply use a bitmap image and rotate it as necessary. I needed a little bit more flexibility (and speed) and used the drawing functions to perform this task.

Assuming you have the ability to draw polygons on the map using local coordinates (pixels), you can manually draw some indicator. For example, this code:

int position_size = 20; 
GPoint gp = FromLatLngToLocal(longlatposition);

Point[] pnts = new Point[4];
pnts[0] = new Point((int)gp.X - (position_size * 2), (int)gp.Y + (position_size * 2));
pnts[1] = new Point((int)gp.X, (int)gp.Y - (position_size * 4));
pnts[2] = new Point((int)gp.X + (position_size * 2), (int)gp.Y + (position_size * 2));
pnts[3] = new Point((int)gp.X, (int)gp.Y + position_size);

float heading_ = 45; //this is where you define how much to rotate
pnts = Rotate(pnts, new PointF(gp.X, gp.Y), heading_); 

g.FillPolygon(new SolidBrush(color), pnts);

Will draw an arrow that looks like this:

enter image description here

The rotate function is a variation from this post: Rotate bunch of points thourgh an origin).

private static PointF[] Rotate(PointF[] point, PointF pivot, double angleDegree)
{
      double angle = angleDegree * Math.PI / 180;
      double cos = Math.Cos(angle);
      double sin = Math.Sin(angle);

      PointF[] rotated = new PointF[point.Length];

      for (int i = 0; i < point.Length; i++)
      {
             float dx = point[i].X - pivot.X;
             float dy = point[i].Y - pivot.Y;

             double x = (cos * dx) - (sin * dy) + pivot.X;
             double y = (sin * dx) + (cos * dy) + pivot.Y;

             rotated[i] = new PointF((float)x, (float)y);
      }

      return rotated;
 }

Now the hard part is incorporating all this using the GMap plugin. There are a few ways you can do this. I personally chose to modify the GMap source code because it gives the most flexibility with working with the pixel coordinates. Another option, assuming you do not want to modify the source, is to create a new polygon overlay and update the points when you want to show a new position and heading. Just remember that the polygon overlay takes coordinate in lng lat, so you will need to do some conversions to make it work properly, especially if you do not want the position indicator to scale with everything else.

I hope this helps.

Community
  • 1
  • 1
T James
  • 490
  • 5
  • 16