Select to view content in your preferred language

Clustering on non geo map view

193
4
3 weeks ago
Labels (1)
nsamar1
New Contributor II

Hi!

I created non-geo map view and placed 1000 of points. 
I want to cluster them using FeatureReduction. 

When i start application i can see:

nsamar1_0-1719924279883.png

 


But when I click "draw cluster" i got an error: 

nsamar1_1-1719924303545.png

 

Pulse Failed: Invalid argument: Not a GCS or PCS

Here is my MainWindow.xaml.cs:

using Esri.ArcGISRuntime.ArcGISServices;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Mapping.Labeling;
using Esri.ArcGISRuntime.Mapping.Popups;
using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.Reduction;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.UI.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Clusters
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private FeatureLayer _layer;
        GraphicsOverlay _theGraphicsOverlays;
        GraphicsOverlay _theGraphicsOverlaysNon;
        private ClusteringFeatureReduction _clusteringFeatureReduction;
        public MainWindow()
        {
            InitializeComponent();
            _ = Initialize();
        }
        

        bool generatePoints = true;
        int countPoints = 200;
        void addIncidents()
        {
            _theGraphicsOverlays = new GraphicsOverlay();

            // Get the graphic collection from the graphics overlay.
            GraphicCollection theGraphicCollection = _theGraphicsOverlays.Graphics;
            SimpleMarkerSymbol theSimpleMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Square, System.Drawing.Color.Red, 28);
            theSimpleMarkerSymbol.Outline = new SimpleLineSymbol();
            theSimpleMarkerSymbol.Outline.Color = System.Drawing.Color.Black;

            List<Graphic> mapPoints = new List<Graphic>();
            List<Graphic> mapPoints1 = new List<Graphic>();

            if (generatePoints)
            {
                Random random = new Random();
                for (int i = 0; i < countPoints; i++)
                {
                    double x = random.Next(0, 2000); // Replace 10000 with your desired range for X coordinates
                    double y = random.Next(-1000, 0); // Replace 10000 with your desired range for Y coordinates
                    double z = 0; // If you need random Z values, generate them here

                    MapPoint point = new MapPoint(x, y, z);

                    var textSymbol = new TextSymbol
                    {
                        Text = $"{x},{y}",
                        Color = System.Drawing.Color.Black,
                        HaloColor = System.Drawing.Color.White,
                        HaloWidth = 2,
                        Size = 4,
                        VerticalAlignment = Esri.ArcGISRuntime.Symbology.VerticalAlignment.Middle,
                        HorizontalAlignment = Esri.ArcGISRuntime.Symbology.HorizontalAlignment.Center
                    };
                    var compositeSymbol = new CompositeSymbol
                    {
                        Symbols = { theSimpleMarkerSymbol, textSymbol }
                    };

                    mapPoints.Add(new Graphic(point, compositeSymbol));
                    mapPoints1.Add(new Graphic(point, compositeSymbol));
                }
            }
            
            theGraphicCollection.AddRange(mapPoints);

            MyMapViewNonGeo.GraphicsOverlays.Add(_theGraphicsOverlays);
        }
       
      
        
        private async void LoadRaster(RasterLayer myRasterLayer)
        {
            await myRasterLayer.LoadAsync();

            await MyMapViewNonGeo.SetViewpointGeometryAsync(myRasterLayer.FullExtent);
        }
        private async Task Initialize()
        {
            //MyMapView.Map = new Map(SpatialReferences.WebMercator);

            MyMapViewNonGeo.Map = new Map();

            string filename = System.IO.Path.GetFullPath(@"C:\Files\QuartzTest\QuartzTest\NonGeo\worldmap-countries-hd.jpg");

            // Create the layer                       
            RasterLayer imageLayer = new RasterLayer(filename);

            LoadRaster(imageLayer);

            MyMapViewNonGeo.Map.Basemap.BaseLayers.Add(imageLayer);


            DrawClustersButton.IsEnabled = true;
            addIncidents();

        }
        private void CreateCustomFeatureReduction()
        {
            try
            {
                // Create a class breaks renderer to apply to the custom feature reduction.
                ClassBreaksRenderer classBreaksRenderer = new ClassBreaksRenderer();
                classBreaksRenderer.DefaultSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Diamond, System.Drawing.Color.White, 24)
                {
                    Outline = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, System.Drawing.Color.FromArgb(0, 122, 204), 2)
                };
                _clusteringFeatureReduction = new ClusteringFeatureReduction(classBreaksRenderer);

                // Set the feature reduction for the layer.
                //_layer.FeatureReduction = _clusteringFeatureReduction;
                var incidents = MyMapViewNonGeo.GraphicsOverlays.First();
                incidents.FeatureReduction = _clusteringFeatureReduction;

                var simpleLabelExpression = new SimpleLabelExpression("[cluster_count]");
                var textSymbol = new TextSymbol()
                {
                    Color = System.Drawing.Color.Black,
                    Size = 15,
                    HaloColor = System.Drawing.Color.White,
                    HaloWidth = 2
                };
                var labelDefinition = new LabelDefinition(simpleLabelExpression, textSymbol) { Placement = LabelingPlacement.PointCenterCenter };

                // Add the label definition to the feature reduction.
                 //_clusteringFeatureReduction.LabelDefinitions.Add(labelDefinition);
                // Populate the cluster radius and max scale pickers with default values.
                 List<double> items = new List<double> { 0, 1, 2, 3, 4, 5, 6, 10, 15, 30, 45, 60, 75, 90, 100,200,300, 1000 };


                ClusterRadiusPicker.ItemsSource = items;
                // Set initial picker values.
                // Note that the default value for cluster radius is 60.
                // Increasing the cluster radius increases the number of features that are grouped together into a cluster.            
                ClusterRadiusPicker.SelectedValue = _clusteringFeatureReduction.Radius;
            }
            catch (Exception ex)
            {

            }
            

            
        }

       
        #region EventHandlers

        private void DisplayLabelsCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            if ((bool)(sender as CheckBox).IsChecked)
            {
                // Create a label definition with a simple label expression.
                var simpleLabelExpression = new SimpleLabelExpression("[cluster_count]");
                var textSymbol = new TextSymbol() { Color = System.Drawing.Color.Black,
                    Size = 15,
                    HaloColor = System.Drawing.Color.White,
                    HaloWidth = 2
                };
                var labelDefinition = new LabelDefinition(simpleLabelExpression, textSymbol) { Placement = LabelingPlacement.PointCenterCenter };

                // Add the label definition to the feature reduction.
                _clusteringFeatureReduction?.LabelDefinitions.Add(labelDefinition);
            }
            else
            {
                _clusteringFeatureReduction.LabelDefinitions.Clear();
            }
        }

        // When a new picker item is selected, update the feature reduction cluster radius.
        private void ClusterRadiusPicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_layer != null)
            {
                ((ClusteringFeatureReduction)_layer.FeatureReduction).Radius = (double)ClusterRadiusPicker.SelectedItem;
            }
            if (_theGraphicsOverlaysNon != null)
            {
                ((ClusteringFeatureReduction)_theGraphicsOverlaysNon.FeatureReduction).Radius = (double)ClusterRadiusPicker.SelectedItem;               
            }
        }


        private void DrawClustersButton_Clicked(object sender, RoutedEventArgs e)
        {
            try
            {
                // Create a new clustering feature reduction.
                CreateCustomFeatureReduction();

                // Show the feature reduction's clustering options.
                ClusteringOptions.Visibility = Visibility.Visible;

                // Hide the draw clusters button.
                DrawClustersButton.Visibility = Visibility.Collapsed;
            }
            catch(Exception ex)
            {

            }
        }

        // Hide and nullify the opened popup when user left clicks.
        private void PopupBackground_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            PopupBackground.Visibility = Visibility.Collapsed;
            //PopupViewer.Popup = null;
        }

        #endregion EventHandlers
    }
}

Here is MainWindow.xaml

<Window x:Class="Clusters.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Clusters"
        xmlns:quartz="http://schemas.esri.com/arcgis/runtime/2013"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <quartz:MapView x:Name="MyMapViewNonGeo" />
        <Border Width="auto"
                Height="auto">
            <StackPanel Orientation="Vertical">
                <Button x:Name="DrawClustersButton"
                        Padding="5"
                        HorizontalAlignment="Center"
                        Click="DrawClustersButton_Clicked"
                        Content="Draw clusters"
                        IsEnabled="False" />
                <Grid x:Name="ClusteringOptions" Visibility="Collapsed">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="2*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.ColumnSpan="2"
                               Padding="5"
                               HorizontalAlignment="Center"
                               FontSize="16"
                               FontWeight="Bold"
                               Text="Clustering Properties" />
                    <TextBlock Grid.Row="1"
                               Grid.Column="0"
                               Padding="5"
                               HorizontalAlignment="Right"
                               VerticalAlignment="Center"
                               FontWeight="Bold"
                               Text="Display labels:" />
                    <CheckBox x:Name="DisplayLabelsCheckBox"
                              Grid.Row="1"
                              Grid.Column="1"
                              VerticalAlignment="Center"
                              Checked="DisplayLabelsCheckBox_Checked"
                              IsChecked="true"
                              Unchecked="DisplayLabelsCheckBox_Checked" />
                    <TextBlock Grid.Row="2"
                               Grid.Column="0"
                               Padding="5"
                               HorizontalAlignment="Right"
                               VerticalAlignment="Center">
                        <Run FontWeight="Bold" Text="Cluster radius:" />
                        <Run Text="{Binding ElementName=ClusterRadiusSlider, Path=Value, Mode=OneWay, StringFormat=n0}" />
                    </TextBlock>
                    <ComboBox x:Name="ClusterRadiusPicker"
                              Grid.Row="2"
                              Grid.Column="1"
                              Width="75"
                              HorizontalAlignment="Left"
                              VerticalAlignment="Center"
                              SelectionChanged="ClusterRadiusPicker_SelectionChanged" />
                    <TextBlock Grid.Row="3"
                               Grid.Column="0"
                               Padding="5"
                               HorizontalAlignment="Right"
                               VerticalAlignment="Center">
                        <Run FontWeight="Bold" Text="Maximum map scale:" />
                        <Run Text="{Binding ElementName=MaxScaleSlider, Path=Value, Mode=OneWay, StringFormat=n0}" />
                    </TextBlock>
                    <TextBlock Grid.Row="4"
                               Grid.Column="0"
                               Grid.ColumnSpan="2"
                               Padding="5"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center">
                        <Run FontWeight="Bold" Text="Current map scale: " />
                        <Run Text="1:" />
                        <Run Text="{Binding ElementName=MyMapView, Path=MapScale, Mode=OneWay, StringFormat=n0}" />
                    </TextBlock>
                </Grid>
                
            </StackPanel>
        </Border>
        <TextBlock x:Name="DistanceTextBlock" Foreground="Black"
                    HorizontalAlignment="Left" VerticalAlignment="Center" 
					Text="Distance between points: " TextWrapping="Wrap" FontWeight="Bold" Margin="28,10,0,395" Height="auto" Width="266"/>
        <Grid x:Name="PopupBackground"
              Background="#AA333333"
              MouseLeftButtonDown="PopupBackground_MouseLeftButtonDown"
              Visibility="Collapsed">
            <Border HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Background="White">
            <!--<quartz:PopupViewer x:Name="PopupViewer"
                                MaxWidth="400"
                                MaxHeight="400"
                                Margin="5"
                                Padding="5" />-->
            </Border>
        </Grid>
    </Grid>
</Window>


My question is do you support clustering at all for Non geo maps, if yes, what should i change to have it working? 
Thanks

0 Kudos
4 Replies
dotMorten_esri
Esri Notable Contributor

Could you try and assign a SpatialReference to the MapPoints you're creating and let me know if that helps.

0 Kudos
nsamar1
New Contributor II

Hi!

Thanks for the reply. 
So, when i added spatial reference WGS84 (on line 10):

if (generatePoints)
            {
                Random random = new Random();
                for (int i = 0; i < countPoints; i++)
                {
                    double x = random.Next(0, 2000); // Replace 10000 with your desired range for X coordinates
                    double y = random.Next(-1000, 0); // Replace 10000 with your desired range for Y coordinates
                    double z = 0; // If you need random Z values, generate them here

                    MapPoint point = new MapPoint(x, y, z, SpatialReferences.Wgs84);

                    var textSymbol = new TextSymbol
                    {
                        Text = $"{x},{y}",
                        Color = System.Drawing.Color.Black,
                        HaloColor = System.Drawing.Color.White,
                        HaloWidth = 2,
                        Size = 4,
                        VerticalAlignment = Esri.ArcGISRuntime.Symbology.VerticalAlignment.Middle,
                        HorizontalAlignment = Esri.ArcGISRuntime.Symbology.HorizontalAlignment.Center
                    };
                    var compositeSymbol = new CompositeSymbol
                    {
                        Symbols = { theSimpleMarkerSymbol, textSymbol }
                    };

                    mapPoints.Add(new Graphic(point, compositeSymbol));
                    mapPoints1.Add(new Graphic(point, compositeSymbol));
                }
            }

I don't see points add all:

nsamar1_0-1719990721370.png

When I changed to WebMercator:

MapPoint point = new MapPoint(x, y, z, SpatialReferences.WebMercator);

 I see points:

nsamar1_1-1719990782948.png

But clustering is still not working:

nsamar1_2-1719990802791.png

 

 

0 Kudos
dotMorten_esri
Esri Notable Contributor

> So, when i added spatial reference WGS84 (on line 10) I don't see points add all:

Yes your spatial reference you use MUST match the spatial reference of your X and Y, whatever that is. Looks like you're just doing random numbers between 0 and 2000, but I wouldn't know what kind of units that is.

0 Kudos
nsamar1
New Contributor II

Yes, i am doing random points, but as you can on my screenshot 

nsamar1_0-1720611401012.png

They are placed. 
I can try to put some specific points, but issue still will be reproducible. 
Clustering will not working. 

Can you provide any information how to make it work with image(raster) layer and clustering of points on it? 

0 Kudos