question to layer (custom provider)

7 posts, 0 answers
  1. Ulrich Fiege
    Ulrich  Fiege avatar
    62 posts
    Member since:
    Sep 2005

    Posted 19 Mar 2010 Link to this post

    We have the following use-case:

    We´ve build a custom map provider, that works. There is one problem:
    An image with the labels of the map have to be overlayed of the hole
    map-view and the label-image have to be requested and updated at every zooming- or panning-action.
    Currently we load the label-image into an Image-control of an informationlayer.
    The events "Zoomchanged" or "Centerchanged" are not useful to update the label-image, because
    they won´t be triggered at the end of the action.
    Are there any other events, like "Zooming-end", "Panning-end" or "Mapview-changed"?

    We tried to use the tilelayer, too. But we can´t change the tilesize-property, because
    it´s readonly. Is it possible to change the tilesize of a tilelayer?

    Best regards
  2. Justin White
    Justin White avatar
    1 posts
    Member since:
    Dec 2003

    Posted 20 Mar 2010 Link to this post

    I agree with Ulrich - we need a couple more events like he mentioned - ZoomEnd and PanEnd would

    My specific case is a little different - I am updating UIElements that are positioned based and found that using the CenterChanged event doesn't quite work because it fires and then the map still moves slower and slower till it stops to not create a jarring stopping effect. Really nice to look at but again - means that the positions are slightly off because of when the event fires...

    Maybe I missed something?

    Excellent control by the way!

    Justin
  3. DevCraft banner
  4. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 24 Mar 2010 Link to this post

    Hi,

    If I quite get your points you are trying to create something like crosshair at the center of the map. I agree that using of the CenterChanged event isn't good enough for this purpose, because it may produce some strange visual effects when panning with mouse. It occurs because this event fires few times when you move mouse when left button is pressed.

    We have crosshair control in our plans for 2010.Q2 release. We also will include some new events which can simplify handling the situations like this.

    By the way, if you need something that is always centered over the map you can simply put a control with transparent background in the same container as RadMap and make it centered -- vertically and horizontally  (like it is done in the example below - green ring).

    To Justing: I've checked how the FrameworkElements are positioned on the map using the CenterChanged event. They are placed right where they should be even after sprig animation. Please, make sure the elements are aligned correctly.You can find below a simple code which adds element to the information layer when map center is changed.

    <UserControl x:Class="Telerik.Silverlight.RadMap.MainPage"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:map="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.DataVisualization"
                 xmlns:layer="clr-namespace:Telerik.Windows.Controls.Map;assembly=Telerik.Windows.Controls.DataVisualization"
                 Width="800"
                 Height="600">
        <Grid x:Name="LayoutRoot">
            <Grid.Resources>
                <DataTemplate x:Key="RingTemplate">
                    <Grid Width="14" Height="14">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="14" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <layer:MapLayer.HotSpot>
                            <layer:HotSpot X="0.5" Y="0.5" />
                        </layer:MapLayer.HotSpot>
                        <Path Fill="Yellow">
                            <Path.Data>
                                <GeometryGroup>
                                    <EllipseGeometry Center="7,7" RadiusX="3" RadiusY="3" />
                                    <EllipseGeometry Center="7,7" RadiusX="7" RadiusY="7" />
                                </GeometryGroup>
                            </Path.Data>
                        </Path>
                    </Grid>
                </DataTemplate>
            </Grid.Resources>
      
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="80*" />
                <ColumnDefinition Width="20*" />
            </Grid.ColumnDefinitions>
      
            <map:RadMap x:Name="radMap" 
                        Center="37.7040701207995,-121.882780875908"
                        ZoomLevel="10"
                        CenterChanged="MapCenterChanged">
                <layer:InformationLayer Name="informationLayer" ItemTemplate="{StaticResource RingTemplate}">
                </layer:InformationLayer>
            </map:RadMap>
      
            <Grid>
                <Grid Width="14" Height="14" HorizontalAlignment="Center" VerticalAlignment="Center">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="14" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <layer:MapLayer.HotSpot>
                        <layer:HotSpot X="0.5" Y="0.5" />
                    </layer:MapLayer.HotSpot>
                    <Path Fill="Green">
                        <Path.Data>
                            <GeometryGroup>
                                <EllipseGeometry Center="7,7" RadiusX="3" RadiusY="3" />
                                <EllipseGeometry Center="7,7" RadiusX="7" RadiusY="7" />
                            </GeometryGroup>
                        </Path.Data>
                    </Path>
                </Grid>
            </Grid>
        </Grid>
    </UserControl>
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Windows.Resources;
    using System.Windows.Data;
    using Telerik.Windows.Controls.Map;
      
    namespace Telerik.Silverlight.RadMap
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
      
                this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            }
      
            private void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                BingMapProvider provider = new BingMapProvider(MapMode.Aerial, true, "YOUR Bing Application ID");
                this.radMap.Provider = provider;
            }
      
            private void MapCenterChanged(object sender, EventArgs e)
            {
                this.informationLayer.Items.Clear();
                this.informationLayer.Items.Add(this.radMap.Center);
            }
        }
    }

    To Ulrich: I am afraid changing the tile size is not possible.

    Regards,
    Andrey Murzov
    the Telerik team


    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  5. Ulrich Fiege
    Ulrich  Fiege avatar
    62 posts
    Member since:
    Sep 2005

    Posted 25 Mar 2010 Link to this post

    Thank you for the example.

    It works fine with build in providers like openstreetmapprovider.
    But with our custom provider, the informationlayer-item is allways displayed in the left-top-corner.
    Please have a look at the attached custom provider class code.
    Could there probably a problem with "SpatialReference" is set to "MercatorProjection"?
    This setting is nescessary for our mapserver.

     
    Imports System  
    Imports System.Windows  
    Imports System.Windows.Browser  
    Imports System.Windows.Controls  
    Imports System.Windows.Media  
    Imports System.Windows.Media.Imaging  
    Imports System.Text.RegularExpressions  
    Imports Telerik.Windows.Controls.Map  
    Imports Telerik.Windows.Controls  
    Imports System.Text  
     
     
    Public Class XserverTileSource  
        Inherits MapProviderBase  
        Public Const TILE_SIZE As Integer = 256 
        Private _IsInitialized As Boolean  
        Private _mapparent As RadMap  
        Private baseUrl As String  
     
        'Constructor Called by XAML instanciation; Wait for MapMode to be set to initialize services  
        Public Sub New(ByVal baseUrl As String)  
            MyBase.New(MapMode.Road, True)  
            Me.baseUrl = baseUrl  
     
            MaxZoomLevel = 17 
            MinZoomLevel = 1 
     
            _IsInitialized = True 
            RaiseEvent InitializeCompleted(Me, Nothing)  
        End Sub  
     
        Public Overloads Overrides ReadOnly Property IsInitialized() As Boolean  
            Get  
                Return _IsInitialized  
            End Get  
        End Property  
     
        ' <summary> 
        ' Gets list of the supported map modes.  
        ' </summary> 
        ' <returns>List of the supported map modes.</returns> 
        Public Overloads Overrides ReadOnly Property SupportedModes() As IEnumerable(Of MapMode)  
            Get  
            End Get  
        End Property  
     
     
        ' <summary> 
        ' Gets value which indicates whether given mode is supported by map provider.  
        ' </summary> 
        ' <param name="mode">Map mode to check.</param> 
        ' <returns>true if given mode is supported. Otherwise - false.</returns> 
        Public Overloads Overrides Function IsModeSupported(ByVal mode As MapMode) As Boolean  
            Return True  
        End Function  
     
        ' <summary> 
        ' Gets value which indicates whether labels are supported by the map provider.  
        ' </summary> 
        Public Overloads Overrides ReadOnly Property IsLabelSupported() As Boolean  
            Get  
                Return False  
            End Get  
        End Property  
     
        ' <summary> 
        ' MapModeChanged handler.  
        ' </summary> 
        Protected Overloads Overrides Sub OnMapModeChanged(ByVal oldMode As MapMode, ByVal newMode As MapMode)  
            If Not Me.IsSuspended Then  
                Me.Initialize()  
            End If  
        End Sub  
     
        ' <summary> 
        ' Initialize provider.  
        ' </summary> 
        Public Overloads Overrides Sub Initialize()  
     
            'Me._IsInitialized = MyBase.IsInitialized  
        End Sub  
     
        ' <summary> 
        ' Returns the SpatialReference for the map provider.  
        ' </summary> 
        Public Overloads Overrides ReadOnly Property SpatialReference() As ISpatialReference  
            Get  
                Return New MercatorProjection()  
            End Get  
        End Property  
     
        Public Overloads Overrides ReadOnly Property TileColor() As Color  
            Get  
                Return Color.FromArgb(255, 255, 254, 185)  
            End Get  
        End Property  
     
        Public Overloads Overrides Function GetTile(ByVal tileLevel As Integer, ByVal tilePositionX As Integer, ByVal tilePositionY As Integer) As Uri  
            If IsInitialized Then  
                Dim zoom As Integer = ConvertTileToZoomLevel(tileLevel)  
     
                Dim quadKey As String = TileXYToQuadKey(tilePositionX, tilePositionY, zoom)  
     
                ' Use the quadkey to determine a bounding box for the requested tile  
                Dim boundingBox As BBox = QuadKeyToBBox(quadKey)  
     
                ' Get the lat longs of the corners of the box  
                Dim lon As Double = XToLongitudeAtZoom(boundingBox.x * TILE_SIZE, 18)  
                Dim lat As Double = YToLatitudeAtZoom(boundingBox.y * TILE_SIZE, 18)  
     
                Dim lon2 As Double = XToLongitudeAtZoom((boundingBox.x + boundingBox.width) * TILE_SIZE, 18)  
     
                Dim lat2 As Double = YToLatitudeAtZoom((boundingBox.y - boundingBox.height) * TILE_SIZE, 18)  
     
                Dim x1 As Double, y1 As Double  
                Wgs_2_Mercator(lon, lat, x1, y1)  
                Dim x2 As Double, y2 As Double  
                Wgs_2_Mercator(lon2, lat2, x2, y2)  
     
                ' Url of Http-Handler, that gets back the tiles as png  
                Dim xmapUrl As StringString = String.Concat(baseUrl, "?left=", System.Convert.ToInt32(CInt(x1)), "&top=", System.Convert.ToInt32(CInt(y1)), "&right=", _  
                System.Convert.ToInt32(CInt(x2)), "&bottom=", System.Convert.ToInt32(CInt(y2)))  
                Dim iru As Uri = New Uri(xmapUrl)  
                Return iru  
            End If  
            Return Nothing  
        End Function  
     
        Public Shared Sub Wgs_2_Mercator(ByVal xArg As Double, ByVal yArg As Double, ByRef xOut As Double, ByRef yOut As Double)  
            Dim lambda As Double, phi As Double  
            lambda = xArg 
            phi = yArg 
            xOut = 6371000.0R * ((Math.PI / 180) * ((lambda) - 0.0R))  
            yOut = 6371000.0R * Math.Log(Math.Tan((Math.PI / 4) + (Math.PI / 180) * phi * 0.5))  
        End Sub  
     
        ''' <summary> 
        ''' Retrieves a quad key from a Virtual Earth tile specifier URL  
        ''' </summary> 
        ''' <param name="url"></param> 
        ''' <returns></returns>  
        Public Function GetQuadKey(ByVal url As String) As String  
            Dim regex = New Regex(".*tiles/(.+)[.].*")  
            Dim match As Match = regex.Match(url)  
     
            Return match.Groups(1).ToString()  
        End Function  
     
        ''' <summary> 
        ''' Returns the bounding BBox for a grid square represented by the given quad key  
        ''' </summary> 
        ''' <param name="quadKey"></param> 
        ''' <param name="x"></param> 
        ''' <param name="y"></param> 
        ''' <param name="zoomLevel"></param> 
        ''' <returns></returns>  
        Public Function QuadKeyToBBox(ByVal quadKey As String, ByVal x As Integer, ByVal y As Integer, ByVal zoomLevel As Integer) As BBox  
            Dim c As Char = quadKey(0)  
     
            Dim tileSize As Integer = 2 << (18 - zoomLevel - 1)  
     
            If cc = "0"c Then  
                yy = y - tileSize  
     
            ElseIf cc = "1"c Then  
                yy = y - tileSize  
                xx = x + tileSize  
     
            ElseIf cc = "3"c Then  
                xx = x + tileSize  
            End If  
     
            If quadKey.Length > 1 Then  
                Return QuadKeyToBBox(quadKey.Substring(1), x, y, zoomLevel + 1)  
            End If  
            Return New BBox(x, y, tileSize, tileSize)  
        End Function  
     
        Public Function QuadKeyToBBox(ByVal quadKey As String) As BBox  
            Const x As Integer = 0 
            Const y As Integer = 262144 
            Return QuadKeyToBBox(quadKey, x, y, 1)  
        End Function  
     
        ''' <summary> 
        ''' Converts radians to degrees  
        ''' </summary> 
        ''' <param name="d"></param> 
        ''' <returns></returns>  
        Public Function RadToDeg(ByVal d As Double) As Double  
            Return d / Math.PI * 180.0R  
        End Function  
     
        ''' <summary> 
        ''' Converts a grid row to Latitude  
        ''' </summary> 
        ''' <param name="y"></param> 
        ''' <param name="zoom"></param> 
        ''' <returns></returns>  
        Public Function YToLatitudeAtZoom(ByVal y As Integer, ByVal zoom As Integer) As Double  
            Dim arc As Double = EarthCircumference / ((1 <zoom) * TILE_SIZE)  
            Dim metersY As Double = HalfEarthCircumference - (y * arc)  
            Dim a As Double = Math.Exp(metersY * 2 / EarthRadius)  
            Dim result As Double = RadToDeg(Math.Asin((a - 1) / (a + 1)))  
            Return result  
        End Function  
     
        ''' <summary> 
        ''' Converts a grid column to Longitude  
        ''' </summary> 
        ''' <param name="x"></param> 
        ''' <param name="zoom"></param> 
        ''' <returns></returns>  
        Public Function XToLongitudeAtZoom(ByVal x As Integer, ByVal zoom As Integer) As Double  
            Dim arc As Double = EarthCircumference / ((1 <zoom) * TILE_SIZE)  
            Dim metersX As Double = (x * arc) - HalfEarthCircumference  
            Dim result As Double = RadToDeg(metersX / EarthRadius)  
            Return result  
        End Function  
     
        Private Shared Function TileXYToQuadKey(ByVal tileX As Integer, ByVal tileY As Integer, ByVal levelOfDetail As Integer) As String  
            Dim quadKey = New StringBuilder()  
            For i As Integer = levelOfDetail To 1 Step -1  
                Dim digit As Integer = 48 
                Dim mask As Integer = 1 << (i - 1)  
                If (tileX And mask) <> 0 Then  
                    digit += 1  
                End If  
                If (tileY And mask) <> 0 Then  
                    digit += 1  
                    digit += 1  
                End If  
                quadKey.Append(Convert.ToChar(digit))  
            Next  
            Return quadKey.ToString()  
        End Function  
     
     
        Public Shared Shadows Event InitializeCompleted As EventHandler  
    End Class  
     
    Public Class BBox  
        Public x As Integer  
        Public y As Integer  
        Public width As Integer  
        Public height As Integer  
     
        Public Sub New(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer)  
            Me.x = x  
            Me.y = y  
            Me.width = width  
            Me.height = height  
        End Sub  
    End Class 
  6. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 25 Mar 2010 Link to this post

    Hi Ulrich,

    The information layer will not arrange its items until the map control is initialized.
    The initialization is completed when the InitializeCompleted event of a map provider is raised.
    The MyBase.IsInitialized property always returns True and raises this event, but I see that it is commented in your code.

    ' <summary>  
    ' Initialize provider.   
    ' </summary>  
    Public Overloads Overrides Sub Initialize()   
        
        'Me._IsInitialized = MyBase.IsInitialized   
    End Sub

    I think you can uncomment it or remove the Initialize method override in order to complete the initialization.

    Greetings,
    Andrey Murzov
    the Telerik team


    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  7. Ulrich Fiege
    Ulrich  Fiege avatar
    62 posts
    Member since:
    Sep 2005

    Posted 29 Mar 2010 Link to this post

    Hi,

    the cod|e "||Me._IsInitialized = MyBase.IsInitialized| " is commented, because it throws an exception:

    Message: The object reference was not specified on an object instance.
    Stacktrace: at Telerik.Windows.Controls.Map.MapCommandBar.SetupMapStyleCommands()
    at Telerik.Windows.Controls.Map.MapCommandBar.OnMapInitialize(RadMap oldMapControl, RadMap newMapControl)
    atTelerik.Windows.Controls.Map.MapBaseControl.MapControlChanged(DependencyObject source, DependencyPropertyChangedEventArgs eventArgs)
    at Telerik.Windows.PropertyMetadata.<>c__DisplayClass1.<Create>b__0(DependencyObject d, DependencyPropertyChangedEventArgs e)
    atSystem.Windows.DependencyObject.RaisePropertyChangeNotifications(DependencyProperty dp, Object newValue, Object oldValue)
    at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet, Boolean isSetByStyle, Boolean isSetByBuiltInStyle, PropertyInvalidationReason reason)
    at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value)
    at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
    at Telerik.Windows.Controls.Map.MapBaseControl.set_MapControl(RadMap value)
    at Telerik.Windows.Controls.RadMap.Initialize()
    at Telerik.Windows.Controls.Map.TileLayer.ProviderInitializeCompleted(Object sender, EventArgs e)
    at Telerik.Windows.Controls.Map.MapProviderBase.get_IsInitialized()
    at TestRadmap.XserverTileSource.Initialize()

    We can´t remove the initialize method, because it´s "mustoverride".

    Greetings
  8. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 30 Mar 2010 Link to this post

    Hello Ulrich,

    The exception occurs because the SupportedModes property returns a Nothing value. Please change it to return empty IEnumerable value like to the following code:
    Public Overloads Overrides ReadOnly Property SupportedModes() As IEnumerable(Of MapMode)
        Get
            Dim Modes As List(Of MapMode) = New List(Of MapMode)
            Return Modes
        End Get
    End Property
    Then un-comment the "Me._IsInitialized = MyBase.IsInitialized" string.

    Greetings,
    Andrey Murzov
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
Back to Top
DevCraft banner