Lasso Selection in RadMap

Environment

Product Version Product Author
2019.1.219 RadMap for WinForms Hristo Merdjanov

Description

An example demonstrating how the objects shown on the map can be selected with lasso rectangle.

Solution

The mouse input in RadMap is handled by a special behavior class exposed by the InputBehavior property of the control. This example will demonstrate how a lasso rectangle can be painted on the map upon moving the mouse. The rectangle will be painted as a MapPolygon object added to a special layer in the map. The layer will be updated every time when the mouse is moved so that it will always contain a single object. After releasing the mouse, the elements which are located in the lasso rectangle will be selected using the SelectElement method of the input behavior class.

MapPin objects will also be added to the map in a separate layer upon double-click. These pins can be later selected with the lasso rectangle and are useful while testing.

In this example, the custom logic for creating the lasso rectangle and adding the pins will only work if the Ctrl key is pressed.

Figure 1: Lasso Selection

map-lasso-selection001

Custom Behavior Class

public class CustomMapInputBehavior : MapInputBehavior
{
    PointG mouseDownCoordinates = PointG.Empty;

    public override void OnMouseDown(MouseEventArgs e)
    {
        this.mouseDownCoordinates = this.GetLocation(e.Location);

        base.OnMouseDown(e);

        foreach (var item in this.MapElement.SelectedElements.ToList())
        {
            PointL pixelLocation = MapTileSystemHelper.LatLongToPixelXY(item.Location, this.MapElement.ZoomLevel);
            RectangleL drawRect = new RectangleL(pixelLocation.X - item.Size.Width / 2, pixelLocation.Y - item.Size.Height, item.Size.Width, item.Size.Height);
            PointL point = new PointL(e.X - this.MapElement.PanOffset.Width, e.Y - this.MapElement.PanOffset.Height);
            if (drawRect.Contains(point))
            {
                this.MapElement.SelectedElements.Remove(item);
                item.BackColor = Color.FromArgb(255, 17, 17, 17);
            }
        }
    }

    public override void OnMouseMove(MouseEventArgs e)
    {
        this.MapElement.Layers["Polygons"].Clear();
        if (e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Control)
        {
            PointG location = this.GetLocation(e.Location);

            if (this.mouseDownCoordinates != PointG.Empty)
            {
                List<PointG> points = new List<PointG>();
                points.Add(this.mouseDownCoordinates);
                points.Add(new PointG(location.Latitude, mouseDownCoordinates.Longitude));
                points.Add(location);
                points.Add(new PointG(mouseDownCoordinates.Latitude, location.Longitude));

                MapPolygon polygon = new MapPolygon(points);
                polygon.BackColor = Color.FromArgb(125, Color.LightGreen);
                this.MapElement.Layers["Polygons"].Add(polygon);
            }
        }
        else
        {
            base.OnMouseMove(e);
        }
    }

    public override void OnMouseUp(MouseEventArgs e)
    {
        base.OnMouseUp(e);

        MapPolygon polygon = this.MapElement.Layers["Polygons"].FirstOrDefault() as MapPolygon;
        if (polygon != null)
        {
            foreach (MapPin item in this.MapElement.Layers["Pins"])
            {
                if (polygon.GeographicBounds.Contains(item.Location))
                {
                    this.SelectElement(item, true);
                    item.BackColor = Color.LightCoral;
                }
            }
        }

        this.mouseDownCoordinates = PointG.Empty;
        this.MapElement.Layers["Polygons"].Clear();
    }

    public override void OnDoubleClick(EventArgs e)
    {
        MouseEventArgs args = e as MouseEventArgs;

        if (args.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Control)
        {
            PointG location = this.GetLocation(args.Location);
            MapPin pin = new MapPin(location);
            this.MapElement.Layers["Pins"].Add(pin);
        }
        else
        {
            base.OnDoubleClick(e);
        }
    }

    private PointG GetLocation(Point mouseLocation)
    {
        PointL point = new PointL(mouseLocation.X - this.MapElement.PanOffset.Width, mouseLocation.Y - this.MapElement.PanOffset.Height);
        PointG location = MapTileSystemHelper.PixelXYToLatLong(point.X, point.Y, this.MapElement.ZoomLevel);

        while (location.Longitude > 180)
        {
            location.Longitude -= 360;
        }

        return location;
    }
}




Public Class CustomMapInputBehavior
    Inherits MapInputBehavior

    Private mouseDownCoordinates As PointG = PointG.Empty

    Public Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        Me.mouseDownCoordinates = Me.GetLocation(e.Location)
        MyBase.OnMouseDown(e)

        For Each item In Me.MapElement.SelectedElements.ToList()
            Dim pixelLocation As PointL = MapTileSystemHelper.LatLongToPixelXY(item.Location, Me.MapElement.ZoomLevel)
            Dim drawRect As RectangleL = New RectangleL(pixelLocation.X - item.Size.Width / 2, pixelLocation.Y - item.Size.Height, item.Size.Width, item.Size.Height)
            Dim point As PointL = New PointL(e.X - Me.MapElement.PanOffset.Width, e.Y - Me.MapElement.PanOffset.Height)

            If drawRect.Contains(point) Then
                Me.MapElement.SelectedElements.Remove(item)
                item.BackColor = Color.FromArgb(255, 17, 17, 17)
            End If
        Next
    End Sub

    Public Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
        Me.MapElement.Layers("Polygons").Clear()

        If e.Button = MouseButtons.Left AndAlso Control.ModifierKeys = Keys.Control Then
            Dim location As PointG = Me.GetLocation(e.Location)

            If Me.mouseDownCoordinates <> PointG.Empty Then
                Dim points As List(Of PointG) = New List(Of PointG)()
                points.Add(Me.mouseDownCoordinates)
                points.Add(New PointG(location.Latitude, mouseDownCoordinates.Longitude))
                points.Add(location)
                points.Add(New PointG(mouseDownCoordinates.Latitude, location.Longitude))
                Dim polygon As MapPolygon = New MapPolygon(points)
                polygon.BackColor = Color.FromArgb(125, Color.LightGreen)
                Me.MapElement.Layers("Polygons").Add(polygon)
            End If
        Else
            MyBase.OnMouseMove(e)
        End If
    End Sub

    Public Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
        MyBase.OnMouseUp(e)
        Dim polygon As MapPolygon = TryCast(Me.MapElement.Layers("Polygons").FirstOrDefault(), MapPolygon)

        If polygon IsNot Nothing Then

            For Each item As MapPin In Me.MapElement.Layers("Pins")

                If polygon.GeographicBounds.Contains(item.Location) Then
                    Me.SelectElement(item, True)
                    item.BackColor = Color.LightCoral
                End If
            Next
        End If

        Me.mouseDownCoordinates = PointG.Empty
        Me.MapElement.Layers("Polygons").Clear()
    End Sub

    Public Overrides Sub OnDoubleClick(ByVal e As EventArgs)
        Dim args As MouseEventArgs = TryCast(e, MouseEventArgs)

        If args.Button = MouseButtons.Left AndAlso Control.ModifierKeys = Keys.Control Then
            Dim location As PointG = Me.GetLocation(args.Location)
            Dim pin As MapPin = New MapPin(location)
            Me.MapElement.Layers("Pins").Add(pin)
        Else
            MyBase.OnDoubleClick(e)
        End If
    End Sub

    Private Function GetLocation(ByVal mouseLocation As Point) As PointG
        Dim point As PointL = New PointL(mouseLocation.X - Me.MapElement.PanOffset.Width, mouseLocation.Y - Me.MapElement.PanOffset.Height)
        Dim location As PointG = MapTileSystemHelper.PixelXYToLatLong(point.X, point.Y, Me.MapElement.ZoomLevel)

        While location.Longitude > 180
            location.Longitude -= 360
        End While

        Return location
    End Function
End Class

Initial Setup

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        this.BackColor = Color.White;

        OpenStreetMapProvider osmProvider = new OpenStreetMapProvider();
        osmProvider.InitializationComplete += delegate(object sender, EventArgs e)
        {
            this.radMap1.BringIntoView(new PointG(40d, -99d), 4);
        };

        this.radMap1.MapElement.Providers.Add(osmProvider);
        MapLayer pinsLayer = new MapLayer("Polygons");
        this.radMap1.Layers.Add(pinsLayer);

        this.radMap1.MapElement.Providers.Add(osmProvider);
        pinsLayer = new MapLayer("Pins");
        this.radMap1.Layers.Add(pinsLayer);

        this.radMap1.InputBehavior = new CustomMapInputBehavior();
    }
}




Public Class RadForm1
    Public Sub New()
        InitializeComponent()
        Me.BackColor = Color.White
        Dim osmProvider As OpenStreetMapProvider = New OpenStreetMapProvider()
        AddHandler osmProvider.InitializationComplete, Sub(ByVal sender As Object, ByVal e As EventArgs)
                                                           Me.RadMap1.BringIntoView(New PointG(40.0R, -99.0R), 4)
                                                       End Sub

        Me.RadMap1.MapElement.Providers.Add(osmProvider)
        Dim pinsLayer As MapLayer = New MapLayer("Polygons")
        Me.RadMap1.Layers.Add(pinsLayer)
        Me.RadMap1.MapElement.Providers.Add(osmProvider)

        pinsLayer = New MapLayer("Pins")
        Me.RadMap1.Layers.Add(pinsLayer)
        Me.RadMap1.InputBehavior = New CustomMapInputBehavior()
    End Sub
End Class

See Also

In this article
Not finding the help you need? Improve this article