Implementing tracks over map

Topics: General Topics
Aug 2, 2007 at 12:01 AM
Recently, I got in my hands an AIS transceiver ( The device can provide through a serial port, data for identification and locating vessels.

I need ideas how to implement the tracks over the map - it would be nice, when one hovers the mouse pointer over a track, to get a tool tip or something like, with the vessel's data. How could I have an event, when the mouse, clicks or hovers a track, in order to display its data?

George J.
Aug 2, 2007 at 12:20 AM
This page might help: Get features from a click on the map.
Aug 2, 2007 at 8:56 AM
Edited Aug 2, 2007 at 8:57 AM
A crude, but working solution:

'determine if we are selecting a unit
'criterion for "selection" of a unit: clicking within 1 radians from a units location

Dim TestPoint, ClickPoint As SharpMap.Geometries.Point, theUnit As Unit
Dim theShortestDistance As Double
ClickPoint = myMap.ImageToWorld(New System.Drawing.PointF(e.X, e.Y))

theShortestDistance = 100

'gather up all "candidate" units (i.e those under the selection threshold)
'and find which is the closest to the point we clicked - and select this unit

For Each KVP As KeyValuePair(Of String, Unit) In myUnits
Dim ThisUnitsDistance As Double
theUnit = KVP.Value
TestPoint = New SharpMap.Geometries.Point(theUnit.Longitude, theUnit.Latitude)
ThisUnitsDistance = TestPoint.Distance(ClickPoint)
If ThisUnitsDistance < 1 Then
If ThisUnitsDistance < theShortestDistance Then
theShortestDistance = ThisUnitsDistance
End If
End If

This allows for clicking "not exactly, but near" a desired object on the map and still selecting it as long as it is the nearest one to the point clicked. You could implement it similarly for a MouseHover event.
Aug 2, 2007 at 4:35 PM
Sorry if this sounds dumb, but I'm still "guessing" my way around SharpMap. How do you get the myUnits collection?
Aug 2, 2007 at 6:44 PM
It's a dictionary-type collection I use to hold the units I want to track and display on the map. It may well be whatever other type of container you use for your objects (array, collection etc.).
Aug 2, 2007 at 9:19 PM
Thanks. So if I get the points from an oledbpoint or postgis/postgis2 table, what do I need to put (or how do I get them) in the collection?
Aug 2, 2007 at 9:33 PM
If you are getting the points from a datastore then it's probably better to follow the example linked above. The reason I am using collections is that my objects are created on-the-fly rather than retrieved from a DB.
Aug 2, 2007 at 9:38 PM
Edited Aug 2, 2007 at 9:40 PM
My problem, which I discuss (more like a monologue so far, lol) in another thread, is that none of the database examples (nor any changes I make to them) is working at getting labels or anything else from the tables... :(

EDIT: i'd be happy to see an example of generating AVL (online vehicle positions and data) objects on the fly, since this is how I started off, with a geometry points collection in a layer. I couldn't get labels on them though.
Aug 2, 2007 at 10:05 PM
Hey Joe;

I am doing something sorta similar to what you are doing. We have a vessel simulation that "runs" a bunch of boats over a network of waterways. While the display of the in-progress data is irrelevant to the final output, it gives a huge wow-factor. What I do is put a sharpmap control on my form and then put a drawing control over that. When I want to zoom or pan the map, I switch the sharpmap to the foreground and let the user pan and zoom, when the map refreshes, I update the background image of my drawing control with the image from the map. I then use the map control to give me the world coordinates of the two corners to cull out any vessels that would not be in the current frame and then get screen coords of each of the remaining vessels which are plotted out. You may ask why on earth did I go through all of the smoke and mirrors and not just use the map control? While I never gave it a chance, my strong bet is that it is not designed to render 60 frames per second while a simple drawing component is going to be very quick. My next step is to tear into the WMS demo project and see if I can add some interesting features to my little map.

Aug 4, 2007 at 12:49 PM
Well, I checked the references codekaizen (Get features from a click on the map) and Dimitris gave me.

The first reference is really a nice approach. One can have a database/datasource with the tracks and just use the ExecuteIntersectionQuery() method to get a dataset with the tracks he just clicked. But there is a problem with the area of searching. The p.GetBoundingBox() method returns a bounding box which is actually a point! It's to difficult to click on a track with the mouse using this bounding box - perhaps if the zoom gets really big, one might click on a track.

I didn't like the second reference, because there is a loop that check all the targets one by one, in order to check if they are near the point that was clicked. The actual criteria here is the variable theShortestDistance, which the user of the application, can not influence, and still is depending on the zoom factor.

Thinking how I could get the best of both, I came up what the user will see on the map, is the point/track as a graphic. This graphic has certain dimensions that are not depending on the zoom factor. So, let's say the point/track is a 10x10 pixel graphic, the right area I should be looking for the target would be the geographical area that this 10x10 pixel graphics is over.

The code is in VB.NET, but it can be converted in C# in case one wants it.

The point of interest here is the pixels variable, which is the half of the width of the point/track graphic. I use this variable to calculate the bounding box that the graphic covers using the GetTargetBoundingBox() method, and the ImagePos variable which is the actual point that was clicked on the map control imageMap:

    Private Sub imageMap_MouseUp(ByVal WorldPos As SharpMap.Geometries.Point, ByVal ImagePos As System.Windows.Forms.MouseEventArgs) Handles imageMap.MouseUp
        Dim fs As New SharpMap.Data.FeatureDataSet
        Dim pixels As Integer = 5
        layTracks.DataSource.ExecuteIntersectionQuery(GetTargetBoundingBox(ImagePos.Location, pixels), fs)
        gridTargets.DataSource = fs.Tables(0)
    End Sub
    Private Function GetTargetBoundingBox(ByVal ImagePos As System.Drawing.Point, ByVal pixels As Integer) As SharpMap.Geometries.BoundingBox
        Dim WorldUpperLeft As SharpMap.Geometries.Point
        WorldUpperLeft = imageMap.Map.ImageToWorld(New Point(ImagePos.X - pixels, ImagePos.Y - pixels))
        Dim WorldLowerRight As SharpMap.Geometries.Point
        WorldLowerRight = imageMap.Map.ImageToWorld(New Point(ImagePos.X + pixels, ImagePos.Y + pixels))
        Return New SharpMap.Geometries.BoundingBox(WorldUpperLeft.X, WorldUpperLeft.Y, WorldLowerRight.X, WorldLowerRight.Y)
    End Function

The technique is quite simple, and I think it can be used also in web apps...

George J.
Aug 4, 2007 at 3:06 PM
I sort of figured by now that the query tool wasn't returning a FeatureDataSet because of the size (or non-size) of the BoundingBox for a point. I came up yesterday with a mix between Dimitris' and gcapnias's methods. It's fast enough to use in the MouseMove event. Normally the distance calculation is only executed once, unless you have points very close together, and if the nearest Point hasn't changed the database isn't queried and the tooltip not updated. I grow the BoundingBox by a percentage of the MapBox size, so it is consistent at any window size and zoom level. Oh, and I am checking for the Query tool for the moment, because I haven't bothered yet to add code to check if all the conditions are met before activating this code (vehicle layer is present and has points, etc).

   Private Sub MapBox1_MouseMove(ByVal WorldPos As SharpMap.Geometries.Point, ByVal ImagePos As System.Windows.Forms.MouseEventArgs) Handles MapBox1.MouseMove
      Dim MyPoint, ThisPoint, MousePoint As SharpMap.Geometries.Point
      Static PrevPoint As SharpMap.Geometries.Point
      Dim PointColl As System.Collections.ObjectModel.Collection(Of SharpMap.Geometries.Geometry)
      Dim ThisDistance, MinDistance As Double
      Dim ID As String = vbNullString, Speed As String = vbNullString
       Dim MyBox As SharpMap.Geometries.BoundingBox
      'Update the position in the status bar:
      tlbLat.Text = WorldPos.X
      tlbLong.Text = WorldPos.Y
      If MapBox1.ActiveTool = SharpMap.Forms.MapBox.Tools.Query Then
         MousePoint = New SharpMap.Geometries.Point(WorldPos.X, WorldPos.Y)
         MyBox = MousePoint.GetBoundingBox
         PointColl = L_geom.DataSource.GetGeometriesInView(MyBox.Grow(MapBox1.Width / 100))
         MinDistance = 9999999999
         If PointColl.Count > 0 Then
            For Each MyPoint In PointColl
               ThisDistance = MyPoint.Distance(MousePoint)
               If ThisDistance < MinDistance Then
                  MinDistance = ThisDistance
                  ThisPoint = MyPoint
               End If
            If ThisPoint.Equals(PrevPoint) Then
               PGcomm.CommandText = "SELECT id_mov,speed FROM " & tablename & " WHERE pos && '" & ThisPoint.ToString & "'"
               PGreader = PGcomm.ExecuteReader
               While PGreader.Read()
                  ID = PGreader(0).ToString()
                  Speed = PGreader(1).ToString()
               End While
               ToolTip1.SetToolTip(MapBox1, ID & ": " & Speed & " km/h")
               PrevPoint = ThisPoint
            End If
         End If
      End If
   End Sub

Aug 4, 2007 at 11:24 PM
Now that I think about it, instead of finding the closest point within the BoundingBox, one could just put them all in the tooltip, on separate lines.
Aug 22, 2007 at 5:44 PM
Help on Sharpmap web js function

I need to do zoom to a point without using ajax updatepanel (don't want the hole page to refresh)

One way i can do this is with callback but then I need to have a javascript function for the following using a html img as a button

How can I write a java function for the following code

ajaxMap.Map.Center = new SharpMap.Geometries.Point(Convert.ToDouble), Convert.ToDouble("-28.107044"));
ajaxMap.Map.Zoom = 0.025;

or is there a easier / better way to do this ?

Dec 1, 2008 at 2:18 AM
Im looking for a sample project in SharpMap, where i can capture the mouse events like mouse move, mouse click (up & down), etc..
Can anyone help me in this regards.