1

Тема: GoogleMaps.Net.Clustering

В проекті windows form C# підключив бібліотеку gmap.net
З бази беру координати об'єктів і додаю до маркерів:

Прихований текст

private void GMapMarkerInit()
        {
            // Створюємо конект до бази
            SqlConnection cs = new SqlConnection(Properties.Settings.Default.DatabaseObjectConnectionString);
            // Оголошуємо адаптер даних
            SqlDataAdapter da = new SqlDataAdapter("SELECT GeoLatitude, GeoLongitude, AddressObject FROM TableAddress", cs);
            // Оголошуємо таблицю з даними
            DataTable dt = new DataTable();
            // Заповнюємо таблицю даними з бази відповідно як побудований адаптер
            da.Fill(dt);            

            // Налаштування та показ свого маркеру
            // Оголошуємо змінну і присвоюємо їй зображення логотип
            Bitmap LogoMarker = (Bitmap)Image.FromFile("Image\\logo32x32.png");
            // Оголошуємо змінну список маркерів
            GMapOverlay markers = new GMapOverlay("markers");            
            // Створюємо на контролі список маркерів
            GMapControl.Overlays.Add(markers);
            
            // 2. Заповнення списку маркерів 
            foreach (DataRow row in dt.Rows)
            {
                try
                {
                    // Оголошуємо змінну маркер з координатами і логотипом
                    GMapMarker markerObject = new GMarkerGoogle(new PointLatLng(Convert.ToDouble(row[0]), Convert.ToDouble(row[1])), LogoMarker)
                    {
                        // Додавання до маркеру підказки написочки
                        ToolTipText = Convert.ToString(row[2]),
                        // Додавання до маркеру тега
                        Tag = "для тесту",
                        // Режим показу підказочки
                        ToolTipMode = MarkerTooltipMode.OnMouseOver
                    };

                    // Додаємо до списку маркерів створений маркер об'єкт
                    markers.Markers.Add(markerObject);
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error");
                }
            }            

            // Звільняємо ресурси
            dt.Dispose();
            da.Dispose();
            cs.Dispose();
            
        }

Це працює.

Є забаганка, щоб була кластерізація доданих маркерів.

В NuGet є бібліотека GoogleMaps.Net.Clustering - додав.

За адресою https://github.com/pootzko/GoogleMaps.Net.Clustering є як користуватись, але я не зміг розібратись як тим користуватись. Прикладів, крім цього, не знайшов.
Є описи про серверну кластерізацію за допомоги SQL запросів до бази. Але я на базах взагалі махровий чайник.

Допоможіть будь ласка.
По логіці в мене є список маркерів markers.Markers тепер якось потрібно згодувати це GoogleMaps.Net.Clustering щоб повернулись змінені маркери в залежності від поточного зума.

2

Re: GoogleMaps.Net.Clustering

Мабуть вже дим з вух і щось не те питаю.

Перефразую мабуть.
Є база з адресами і координатами. З бази даних заповнюю datatable:

// Створюємо конектор до бази
            SqlConnection cs = new SqlConnection(Properties.Settings.Default.DatabaseObjectConnectionString);
            // Оголошуємо адаптер даних
            SqlDataAdapter da = new SqlDataAdapter("SELECT GeoLatitude, GeoLongitude, AddressObject FROM TableAddress", cs);
            // Оголошуємо таблицю з даними
            DataTable dt = new DataTable();
            // Заповнюємо таблицю даними з бази відповідно як побудований адаптер
            da.Fill(dt);

В NuGet є бібліотека GoogleMaps.Net.Clustering - додав.
За адресою https://github.com/pootzko/GoogleMaps.Net.Clustering є як користуватись. Мені не зрозуміло взагалі як.

Як мені згодувати бібліотеці GoogleMaps.Net.Clustering данні з dt, щоб отримати список маркерів вже кластеризованих?

3

Re: GoogleMaps.Net.Clustering

а що саме вам не зрозуміло з пояснення?

public IList<MapPoint> GetClusters(YourFilterObj filter)
{
    var clusterPointsCacheKey = "somecachekey";
    var points = GetClusterPointCollection(clusterPointsCacheKey);

    var mapService = new ClusterService(points);
    var input = new GetMarkersParams()
    {
        NorthEastLatitude = filter.NorthEastLatitude,
        NorthEastLongitude = filter.NorthEastLongitude,
        SouthWestLatitude = filter.SouthWestLatitude,
        SouthWestLongitude = filter.SouthWestLongitude,
        ZoomLevel = filter.ZoomLevel,
        PointType = clusterPointsCacheKey
    };

    var markers = mapService.GetClusterMarkers(input);

    return markers.Markers;
}

private PointCollection GetClusterPointCollection(string clusterPointsCacheKey)
{
    var points = new PointCollection();
    if (points.Exists(clusterPointsCacheKey))
        return points;

    var dbPoints = GetPoints(); // Get your points here
    var mapPoints = dbPoints.Select(p => new MapPoint() { X = p.X, Y = p.Y }).ToList();
    var cacheDuration = TimeSpan.FromHours(6);
    points.Set(mapPoints, cacheDuration, clusterPointsCacheKey);

    return points;
}
Говоріть українською! Живіть українською! Відчувайте українською!

4

Re: GoogleMaps.Net.Clustering

FakiNyan написав:

а що саме вам не зрозуміло з пояснення?

Мабуть все не зрозуміло. Спробую розібрати по порядку, як буде кому ласка, направте/поправте/підкажіть.

Функція вертає колекцію об'єктів (MapPoint) доступних по індексу. Функція на вхід що приймає? Не зрозуміло мені. На "YourFilterObj" помилка "Error CS0246 The type or namespace name 'YourFilterObj' could not be found"

public IList<MapPoint> GetClusters(YourFilterObj filter)

Це для чого? Зрозуміло, що "somecachekey" це тут щось своє дописати, але призначення не розумію.

var clusterPointsCacheKey = "somecachekey";

Викликаємо функцію GetClusterPointCollection яка повертає колекцію точок (кластерів?). На вхід "somecachekey" це щось типу тєга колекції?

var points = GetClusterPointCollection(clusterPointsCacheKey);

Оголошуємо невизначеного типу змінну mapService = новий об'єкт ClusterService, якому згодовано колекцію точок "points".

var mapService = new ClusterService(points);

Змінній input передаємо параметри кластеризованого маркеру? Я так розумію координати прямокутника де об'єднаються всі маркери, які входять до цього прямокутника, в один маркер. Плюс рівень зуму, плюс тип маркеру. Ці параметри беруться з структури filter, яка дається на вхід функції. Як мені той filter сформувати?

var input = new GetMarkersParams()
            {
                NorthEastLatitude = filter.NorthEastLatitude,
                NorthEastLongitude = filter.NorthEastLongitude,
                SouthWestLatitude = filter.SouthWestLatitude,
                SouthWestLongitude = filter.SouthWestLongitude,
                ZoomLevel = filter.ZoomLevel,
                PointType = clusterPointsCacheKey
            };

створюємо маркер згідно параметрів в input.

var markers = mapService.GetClusterMarkers(input);

Повертаємо колекцію кластеризованих маркерів.

return markers.Markers;

Функція яка повертає колекцію точок на вхід щось типу тегу групи точок, чи назва групи точок?

private PointCollection GetClusterPointCollection(string clusterPointsCacheKey)

Оголошуємо нову колекцію точок

var points = new PointCollection();

Оголошуємо типу бази з точок де GetPoints() мабуть якась моя функція з видобутку тих самих точок в форматі mappoint?

 var dbPoints = GetPoints();

Це для чого?

var cacheDuration = TimeSpan.FromHours(6);

Якась установка параметрів точок?

points.Set(mapPoints, cacheDuration, clusterPointsCacheKey);

Повертаємо колекцію точок

return points;

Ну і відповідно не розумію як мені цими двома функціями користуватись. Що дати на вхід, а як отримаю результат як ним скористатись?
Не вистачає живого прикладу, вже б напевно зміг би второпати.

p.s. Вже думав зробити свій обробник кластерізації на основі адреси об'єкта. Типу зум 7 - групуємо маркери по області, збільшуємо зум - вже за містом групуються, а далі вже без кластерізації. Але тоді постане питання в строгій типизації вводу адреси об'єктів. Бо область можуть вводити як Дніпропетровська, Днепропетровская, Dnipropetrovskaya, тощо. Чи там місто Дніпро, Дніпропетровськ, Dnipro, Січеслав, тощо. З Кропівницьким та ж сама біда. Або десь отримати типизований список областей і міст, і вулиць можна, що б ними заповнити комбобокси і вже звідти додавати адреси до бази. Але це не "правильний" підхід на мою думку. Треба до координат прив'язуватись все ж таки.

5

Re: GoogleMaps.Net.Clustering

там написано, що той проект форк ось цього https://github.com/kunukn/Google-Maps-Clustering-CSharp
і ось туто є якісь пояснення https://kunuk.wordpress.com/2011/11/05/ … h-asp-net/ то почитайте ось це, а потім може щось проясниться

Говоріть українською! Живіть українською! Відчувайте українською!

6

Re: GoogleMaps.Net.Clustering

Та я вже всі посилання переглянув куди посилалось. Ніяких прояснень, на жаль. Шкода.

7

Re: GoogleMaps.Net.Clustering

Трішки розвиднялось, але ще не зовсім. Будь ласка допомагайте.

Є бібліотека GoogleMaps.Net.Clustering.
За адресою https://github.com/pootzko/GoogleMaps.Net.Clustering є як користуватись. Там дві функції:

Прихований текст

public IList<MapPoint> GetClusters(YourFilterObj filter)
        {
            var clusterPointsCacheKey = "somecachekey";
            var points = GetClusterPointCollection(clusterPointsCacheKey);

            var mapService = new ClusterService(points);
            var input = new GetMarkersParams()
            {
                NorthEastLatitude = filter.NorthEastLatitude,
                NorthEastLongitude = filter.NorthEastLongitude,
                SouthWestLatitude = filter.SouthWestLatitude,
                SouthWestLongitude = filter.SouthWestLongitude,
                ZoomLevel = filter.ZoomLevel,
                PointType = clusterPointsCacheKey
            };

            var markers = mapService.GetClusterMarkers(input);

            return markers.Markers;
        }

private PointCollection GetClusterPointCollection(string clusterPointsCacheKey)
        {
            var points = new PointCollection();
            if (points.Exists(clusterPointsCacheKey))
            {
                return points;
            }

            var dbPoints = GetPoints(); //Отримуємо наші точки тут
            var mapPoints = dbPoints.Select(p => new MapPoint() { X = p.X, Y = p.Y }).ToList();
            var cacheDuration = TimeSpan.FromHours(6);
            points.Set(mapPoints, cacheDuration, clusterPointsCacheKey);

            return points;
        }

Що роблю я:
- додаю клас YourFilterObj:

public class YourFilterObj
    {
        public double NorthEastLatitude { get; set; }
        public double NorthEastLongitude { get; set; }
        public double SouthWestLatitude { get; set; }
        public double SouthWestLongitude { get; set; }
        public int ZoomLevel { get; set; }
    }

Додаю функцію отримання списку точок об'єктів:

private List<MapPoint> GetPoints()
        {
            List<MapPoint> mapPoint = new List<MapPoint>();

            using (SqlConnection cs = new SqlConnection(Properties.Settings.Default.DatabaseObjectConnectionString))
            {                
                SqlDataAdapter da = new SqlDataAdapter("SELECT GeoLatitude, GeoLongitude FROM TableAddressObj", cs);
                DataTable dt = new DataTable();
                da.Fill(dt);

                foreach (DataRow row in dt.Rows)
                {
                    try
                    {                        
                        mapPoint.Add(new MapPoint(Convert.ToDouble(row[0]), Convert.ToDouble(row[1])));
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "Error");
                    }
                }
            }
            return mapPoint;            
        }

На кнопку вішаю подію яка має мої видимі маркери кластеризувати:

private void Button1_Click(object sender, EventArgs e)
        {
            gMapControl.Overlays.Clear();

            YourFilterObj region = new YourFilterObj()
            {
                NorthEastLatitude = gMapControl.FromLocalToLatLng(0, 0).Lat,
                NorthEastLongitude = gMapControl.FromLocalToLatLng(0, 0).Lng,
                SouthWestLatitude = gMapControl.FromLocalToLatLng(gMapControl.Width, gMapControl.Height).Lat,
                SouthWestLongitude = gMapControl.FromLocalToLatLng(gMapControl.Width, gMapControl.Height).Lng,
                ZoomLevel = 7
            };

            Bitmap LogoMarker = (Bitmap)Image.FromFile("Image\\logo64x64.png");
            // Оголошуємо змінну список маркерів
            GMapOverlay markers = new GMapOverlay("markers");
            // 1. Створюємо на контролі список маркерів (щоб маркери відображались коректно потрібно створити список, а потім накидати туди маркерів)
            gMapControl.Overlays.Add(markers);

            IList<MapPoint> mapPoint = GetClusters(region);

            foreach (MapPoint point in mapPoint)
            {
                GMapMarker markerObject = new GMarkerGoogle(new PointLatLng(point.Lat, point.Long), LogoMarker)
                {
                    ToolTipText = "перевірка",
                    Tag = "для тесту",
                    ToolTipMode = MarkerTooltipMode.OnMouseOver
                };

                markers.Markers.Add(markerObject);
            }

            gMapControl.Refresh();
        }

Компілюється без помилок. Під час виконання з помилками не вилітає. Але повертається мапа взагалі без маркерів. Гляньте по коду чи не де не накосячив? Може я не вірно бібліотекою користуюсь? Щось зовсім туго йде ця кластерізація.

8

Re: GoogleMaps.Net.Clustering

може картинку не завантажило?

Говоріть українською! Живіть українською! Відчувайте українською!

9

Re: GoogleMaps.Net.Clustering

FakiNyan написав:

може картинку не завантажило?

З картинкою в порядку. Поодинокі ж маркери показує (там теж картинка маркерів та сама).

10

Re: GoogleMaps.Net.Clustering

напишіть може розробнику цьої бібліотеки, та запитайтесь?

Говоріть українською! Живіть українською! Відчувайте українською!

11

Re: GoogleMaps.Net.Clustering

Пройшовся дебагером в цій функції:

public IList<MapPoint> GetClusters(YourFilterObj filter)
        {
            var clusterPointsCacheKey = "somecachekey";
            var points = GetClusterPointCollection(clusterPointsCacheKey); // тут повертається 7 точок з координатами
 
            var mapService = new ClusterService(points); // тут ще є ці 7 точок
            var input = new GetMarkersParams() // координати прямокутника мапи що ми бачимо на моніторі
            {
                NorthEastLatitude = filter.NorthEastLatitude,
                NorthEastLongitude = filter.NorthEastLongitude,
                SouthWestLatitude = filter.SouthWestLatitude,
                SouthWestLongitude = filter.SouthWestLongitude,
                ZoomLevel = filter.ZoomLevel,
                PointType = clusterPointsCacheKey
            };
 
            var markers = mapService.GetClusterMarkers(input);
 
            return markers.Markers; // тут вже повертається count = 0; нічого.
        }

ну і звісно що далі вже нічого й не покаже. От блін. Шось з бібліотекою не то?