Здравствуйте!
Хочу рассказать об кластеризации (группировке) геокоординат на стороне БД. Хотелось бы все это сделать в максимально простом виде, используя школьную математику. На работе появилась задача "отображение тепловой карты пожаров в МО". Пожары представлены виде географических координат. Нужно сгруппировать пожары, которые находятся в определенном радиусе, и на основе этих данных построить тепловую карту.
Готовые решения
Можно использовать стандартный тип geography Sql Server и с помощью distance процедуры рассчитать расстояния между точками и группировать их. Этот способ дорогой по времени, больше 10000 записей занимает примерно 5 минут на core i5 9600к.
Также можно использовать Tile38 (https://tile38.com/) не было времени внедрять, скорость вычисления идеальная. Но нет интеграции с SqlServer и для этого придеться синхронизировать координаты, и обеспечить отказаустойчивость для обеих систем.
Решение
Для решения задачи будем использовать округление координат, так как округление нам нужно в метрах, а координаты представлены в градусах. Долгота зависит от широты и это надо учитывать, когда будем преобразовывать метры в градусы.

Широту можно округлить не зависимо, например:
один градус широты = 2 * Pi * "Полярный радиус земли" / 360 ~ 111 км.
И так как по широте максимум может быть 90 градусов, получается ~ 9985 км. Это число нужно для того чтобы определить коэффициент разбиения по группам. Например Требуется округлить в радиусе 100 км, получается по широте может поместится ~ 100 групп. Итак, нам нужно еще получить до какой степени нужно округлить, - это мы получим следующей формулой.
6 - lg "масштаб группировки в метрах" - оставляем только целую часть
например 6 - lg 100000м = 1 и так нужно округлять первую цифру после запятой.
Итого формула для широты
declare @metersLatDegree float = round(9985238.0901698 / @maxMeters, 0);
declare @latituteCenter float = Round(Round(@latitude * @metersLatDegree / 90.0, 0) * (90.0 /@metersLatDegree), @precsion);
где @maxMeters это максимальная разница между координатами в метрах, @latitude широта, @precsion - степень округления.
Переходим к долготе и она будет зависеть от широты, так как при приближении к полюсу его периметр будет уменьшаться от ~ 40000 км до 0. и для того чтобы определить периметр нужно использовать cos(широты) по след формуле:
один градус долготы = 2 * Pi * "экваториальный радиус земли" * COS(широты) / 360 ~ 111 км. на экваторе когда широта равна 0 и когда широта равна 60 ~ 55 км.
Итоговая формула для долготы почти такая же
declare @metersLatDegree float= round(
20037077.9445957 * cos(radians(@latitude)) / @maxMeters, 0);
declare @longitudeCenter float = Round(Round(@longitude * @metersLatDegree / 90.0, 0) * (90.0 /@metersLatDegree), @precsion);
@longitude - долгота
Чтобы получить @precsion формула одинаковая
@precsion int = 6 - round(log(@maxMeters), 10), 0)
Визуализируем результат для случайных 1000 точек по земле

на полюсах погрешность хромает, но для моего проекта подошло.