Partager via


EnvelopeCenter и EnvelopeAngle

В практических задачах бывает нужно знать геометрический центр и размеры фигуры, например, чтобы правильно спозиционировать ее на экране. В географии полезными методами для этого являются сабж. Как не вполне внятно написано в BOL, метод EnvelopeAngle() "возвращает максимальный угол между точкой, которая возвращена функцией EnvelopeCenter(), и точкой в экземпляре geography в градусах". Догадаться, что в данном случае под вершиной угла понимается центр Земли, предоставляется читателю. Для начала разберемся с EnvelopeCenter(). Это просто. Если из центра Земли протянуть радиус-векторы ко всем точкам фигуры, всех их между собой сложить и поделить на их кол-во, то EnvelopeCenter - это точка на поверхности, куда будет указывать получившийся средний вектор. Аналогом EnvelopeCenter в плоской равномерной геометрии выступает метод STCentroid(). Однако центроид может применяться только к многоугольникам (Polygon или MultiPolygon), а EnvelopeCenter к любым типам фигур. Но в географии. Но вчера. Но по три (с). В принципе, ограничение STCentroid() на многоугольники не представляется излишне суровым, т.к. дуги можно с желаемой точностью саппроксимировать в ломаные при помощи метода CurveToLineWithTolerance().

 

Взяв в качестве примера построенный в предыдущем посте многоугольник, найдем центр Москвы в пределах МКАДа как EnvelopeCenter этого многоугольника и посмотрим, насколько далеко он отстоит от нулевого километра.

 

declare @c geography = @m.EnvelopeCenter()

declare @z geography = geography::Point(55.755831, 37.617673, 4326)

select @c.STBuffer(500), 'EnvelopeCenter' union all select @z.STBuffer(500), 'Нулевой километр' union all select @m, 'Нерезиновая'

select @c.STDistance(@z)

--------------------------------------------------------------------------------------------------------------------------------------

1240.40503111262

 

image

Рис.1

 

Чтобы сделать точки заметными на карте, я изобразил вокруг каждой кружочек радиусом 500 м - STBuffer(500). Фиолетовой точкой показан геометрический центр (EnvelopeCenter), бордовой 1240.4 м на северо-восток - нулевой километр. В принципе, в масштабах мегаполиса не такое уж большое расхождение.

 

Зафиксируем радиус-вектор, проведенный из центра Земли в центр фигуры на ее поверхности. EnvelopeAngle - это угол между ним и самым оттопыреным от него из пучка радиус-векторов, торчащих из центра Земли и упирающихся в точки фигуры.

 

Построим окружность с центром в центре Москвы радиусом EnvelopeAngle, пересчитанным из угловых единиц в метры.

 

declare @c geography = @m.EnvelopeCenter()

select @m.EnvelopeAngle()

declare @x geography = geography::Point(@c.Lat, @c.Long + @m.EnvelopeAngle(), 4326)

declare @y geography = geography::Point(@c.Lat + @m.EnvelopeAngle(), @c.Long, 4326)

select @c.STBuffer(500)

union all

select @c.STBuffer(@c.STDistance(@x))

union all

select @c.STBuffer(@c.STDistance(@y))

union all

select @m

--------------------------------------------------------------------------------------------------------------------------------------

0.175893808517179

 

image

Рис.2

 

К сожалению, нет возможности управлять цветами на закладке Spatial results. Остается довольствоваться эстетическими чувствами разработчиков SSMS, которые их иногда подводят. Угловое расстояние от центра (Рис.1) до самой удаленной точки МКАД составляет (EnvelopeAngle) 0.176 градуса. Градус нужно перевести в лиметры, чтобы нарисовать окружность с помощью STBuffer(). Для этого я создаю точку @y, которая сдвинута на EnvelopeAngle от центра по широте вверх, и измеряю расстояние STDistance от нее до центра. Этот круг показан синим цветом. Круг бордового цвета приведен для сравнения - что будет, если градусный радиус переводить в расстояние по долготе. Бордовый радиус равен расстоянию от центра до точки @x, которая сдвинута на EnvelopeAngle не по меридиану, как @y, а по параллели. Чем дальше от экватора, тем параллели уже - тем меньше метров содержится в градусе долготы. В случае идеальной сферы сечение проходящей через центр в любом направлении плоскостью дает окружность, равную экватору или меридиану. Одинаковое угловое расстояние на каждой из них даст одинаковое линейное. Для реальной Земли это, разумеется, не так, да и в сечении будет не совсем окружность, однако откладывать EnvelopeAngle по меридиану, как мы видим, будет ближе к истине, чем по параллели.

 

2 * EnvelopeAngle не есть диаметр фигуры, он заведомо больше. Под диаметром понимается максимальное расстояние между принадлежащими ей точками. EnvelopeAngle есть максимальное расстояние между EnvelopeCenter и точками фигуры. В силу своего определения EnvelopeCenter не обязан лежать на диаметре, поэтому он гарантированно будет касаться одной точки фигуры, той, которая удалена от него на EnvelopeAngle, но не двух. Синий круг касается МКАД в районе ЮЮВ. На северо-западе МКАД хоть и подходит близко к границе круга, все же находится строго внутри, не задевая ее. Метода STDiameter() в стандарте OGC и реализации SQL Server нет.

 

Продолжение следует.

 

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