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 Answers
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))

- 21
- 2
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:
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.