Partager via


Определение простых циклов-2

Продолжение поста "Определение простых циклов плоского связного графа".

 

Короче, как я и думал, все тривиально. Какой я молодец, что оставил отладочную выдачу.

По задумке в результате последнего вызова перед восхищенными зрителями должен был нарисоваться внешний контур нашей необъятной Родины. Поначалу она так и пошла его очерчивать от фрагмента границы №1 на Чукотке по часовой стрелке (потому что внутренней областью этого региона является вся окружающая плоскость, то есть для нее это, как и для всех, против часов) и благополучно добралась до юга Камчатки. На юге Камчатки имеется фрагмент границы очень маленькой длины.

image

Рис.1

 

select g.STLength() from dbo.RegionsBoundaryFragments where id = 419 --6534.55890860261

 

Когда процедура BuildRegionBoundary до него доходит, у нее по причине его малости съезжает крыша:

image

Рис.2

Видите, когда она ищет продолжение куска границы №418, в кач-ве кандидатов рассматриваются не только начало следующего куска №419 (как должно было бы быть по уму), но и его конец и начало послеследующего куска №420. Почему граница попилена на такие неравномерные LINESTRINGи - вопрос не ко мне. В таком виде карта лежала в .e00 (см. пост "Как я затаскивал в таблицу карту"). Лично меня бы больше устроило, если каждый LINESTRING был бы изначально равен границе своего региона, чтобы не упражняться в курсе "Начальные алгоритмы теории графов средствами SQL". Но в дареном конспекте на почерк не смотрят. Изо всех кандидатов, как мы помним, отбирается с наибольшим синусом между вектором окончания и вектором продолжения. Конец предыдущего и начало следующего - это одна жирная точка, просто в нашем случае она имеет толщину эпсилон. Наибольший синус оказывается у вектора продолжения, который идет от конца куска 419 к его началу (-419 на первом месте в третьем резалтсете), поэтому она разворачивается и преспокойно идет назад. Дура. Кто ж такой криворукий тебя писал? Первым поворотом налево теперь оказывается граница между Корякским АО и Камчатской обл., поэтому она съезжает туда и довершает обход Камчатской области, как если бы ей сказали exec BuildRegionBoundary @fragment = -419, @eps = 10000. 

Проблема, как и ожидалось, в правильном подборе эпсилон. Сбой происходит из-за того, что 10000 - это много. С горя я его уменьшил до 1000 и все прекрасно заработало. Вот и чудно, я уж было опасался, что придется его делать адаптивным.

update dbo.RegionsBoundaryFragments set region = null

exec BuildRegionBoundary @fragment = 1, @eps = 1000

--00:01:34

--select * from RegionsBoundaryFragments where region = 1

select dbo.OrderedBoundaryToPolygon(1)

image

Рис.3

 

Хотя SSMS опять отсебятничает. Корректно ей следовало бы закрасить всю плоскость, кроме России, потому что внутренней областью данного региона является дополнение.

 

Определяем остальные регионы:

 

update dbo.RegionsBoundaryFragments set region = null where region > 1

set nocount on

 

declare @fragment int

while 1 = 1 begin

 select top 1 @fragment = id from RegionsBoundaryFragments where region is null

 if @@rowcount = 0 break

 exec BuildRegionBoundary @fragment = @fragment, @eps = 1000

end

 

set nocount off

--00:05:19 (отладочная выдача в процедуре выключена)

select * from RegionsBoundaryFragments  

Скрипт 1

 

image

Рис.4

 

По мере того, как скрипт работает, с другого соединения можно наблюдать за прогрессом определения регионов:

 

image

Рис.5

 

По окончании нахождения регионов превращаем их в многоугольники:

 

if object_id('RegionPolygons', 'U') is not null drop table RegionPolygons

go

select region, dbo.OrderedBoundaryToPolygon(region) g into RegionPolygons from RegionsBoundaryFragments group by region

--00:00:12

select * from RegionPolygons

Скрипт 2

 

image

Рис.6

 

QED. Аплодисменты.

 

 

Алексей Шуленин