Расчет ориентации каждой стороны многоугольника с помощью ArcPy?

9

Я хочу проверить ориентацию каждой линии в многоугольнике, чтобы я мог рассчитать их солнечную экспозицию. Каждый многоугольник представляет собой здание и имеет соответствующую высоту. На данный момент я просто хочу рассмотреть ориентацию, а позже рассмотрю вопросы затенения.

Один из подходов, который я подумал, состоял в том, чтобы разбить многоугольник на линии и вычислить ориентацию каждой линии, но сложность заключается в том, что мне затем нужно определить внешнюю грань этой линии. Хотя большинство полигонов представляют собой простые четырехсторонние фигуры с прямыми линиями, есть небольшое число, где это не так (вопрос, который я просто хочу рассмотреть, но пока не должен решать).

Я знаком с Python и планировал делать все это из сценария.

djq
источник
1
Помогут
Шон,
@Sean - спасибо, да, это помогает в целом. Я не знаком с конкретными командами ArcGIS, которые можно использовать для этого. Кроме того, остается проблема определения внутренней / внешней грани линии в многоугольнике.
DJN
Когда вы говорите «ориентация», вы не достаточно точно определили ее для меня - например, какова ориентация идеального шестиугольника?
Дан С.
@Dan S. Я только что отредактировал свой ответ, чтобы включить ориентацию каждой линии в многоугольнике.
djq
извините, ответчики - вчера мне не удалось правильно назначить награду.
djq

Ответы:

6

Если вам нужна ориентация на большинство, посмотрите ответ @Mapperz выше.

В противном случае, как вы говорите, вы можете разбить полигоны на линии, используя инструмент Polygon To Line . Это добавляет левое и правое поле FID, где поле равно -1, если нет внешнего многоугольника - это может привести к небольшому разбросу, хотя, если ваши здания находятся рядом или перекрываются.

Оттуда вы можете разделить свои линии в каждой вершине (возможно, использовать разделение на линии COGO ), а затем вычислить углы на каждой из линий (возможно, путем обновления атрибутов COGO ).

Предполагая, что ваше угловое поле рассчитано с севера, аспект будет правильным, где left_FID равен -1, а чтобы получить аспект, когда right_FID равен -1, просто добавьте 180 °. Затем на основе исходного FID вы можете агрегировать, получать мажоритарный аспект на основе длины и т. Д.

Инструмент Polygon to line предназначен для сценариев (насколько я знаю), а инструменты COGO - нет, поэтому вам придется придумывать что-то там самостоятельно.

Надеюсь это поможет!

om_henners
источник
2
Беззастенчивый плагин и комментарий. Во-первых, если у вас нет лицензии Info, code.google.com/p/boundary-generator делает более или менее то же самое, что и инструмент Polygon to Line. Во-вторых, это дает вам гораздо больше информации, чем просто взгляд на какую-то общую ориентацию всего многоугольника ... например, вы можете использовать полученную таблицу для гораздо более точных расчетов солнечного освещения, принимая во внимание аспект каждой отдельной стены ,
Дан С.
5

Нахождение ориентации

Внутри сценария многоугольник будет доступен в виде набора колец - одно внешнее кольцо и ноль или более внутренних колец - причем каждое кольцо представлено циклически упорядоченным набором векторов (v [0], v 1 , ... , v [m-1], v [m] = v [0]). Каждый вектор дает координаты вершины (без совпадения двух последовательных вершин). Из этого, как указывали другие, легко получить нормальные векторы (то есть векторы, перпендикулярные направлениям ребер):

n [i] = t (v [i + 1] - v [i]).

Операция "t" поворачивает вектор на 90 градусов против часовой стрелки :

t ((x, y)) = (y, -x).

Только направления этих нормальных векторов имеют значение, поэтому измените их масштаб, чтобы иметь единичную длину: вектор (x, y) масштабируется до (x / s, y / s), где s = Sqrt (x ^ 2 + y ^ 2) (что длина его соответствующего ребра). Теперь давайте предположим, что это было сделано. Запишите компоненты результирующих единичных нормальных векторов как

n [i] = (u [i], v [i]), i = 0, 1, ..., m-1.

Отличительные снаружи изнутри

Как вы заметили, это оставляет двусмысленную направленность: должны ли мы использовать n [i] или -n [i]? Который указывает наружу? Этот вопрос эквивалентен нахождению степени от гауссова отображения . Чтобы вычислить его, вам нужно сложить углы, на которые меняются нормальные направления, когда вы идете вокруг кольца. Поскольку нормальные векторы имеют единичную длину, косинус угла между двумя последовательными ребрами равен

Cos (q_i) = n [i]. n [i + 1] = u [i] * u [i + 1] + v [i] * v [i + 1], i = 0, 1, ..., m-1.

(Определите n [m] = n [0].)

Синус угла между двумя последовательными ребрами

Грех (q_i) = n [i]. t (n [i + 1]) = u [i] * v [i + 1] - v [i] * u [i + 1].

(Обратите внимание, что для этих расчетов пока требуются только суммы, разности и произведения.) Применение основной функции обратной касательной (ATan2) к любой такой паре (косинус, синус) дает угол q_i между -180 и 180 градусами. Суммирование этих углов для i = 0, 1, ..., n-1 дает (с точностью до ошибки с плавающей запятой) общую кривизну кольца, которая должна быть кратна 360 градусам; для замкнутого несамопересекающегося кольца оно будет либо +360, либо -360. В первом случае степень равна 1, а во втором случае степень равна -1. Все нормали ориентированы наружу, когда степень внешнего кольца равна +1, а степени внутренних колец равны -1. При необходимости переориентируйте их кольцо за кольцом в соответствии с этим правилом. То есть, если степень любого кольца противоположна той, которая необходима, отрицайте все нормали для этого кольца. Теперь вы можете приступить к расчетам инсоляции.

Whuber
источник
Спасибо за очень полный ответ. Когда вы говорите: «Внутри скрипта полигон будет доступен в виде набора колец», как этот полигон доступен? Хотя я знаком с некоторыми сценариями Python, я не знаю, как интерпретировать полигон таким образом. Я читаю это медленно и пытаюсь понять, но мне трудно перевести некоторые объяснения в псевдокод, который я могу написать.
DJN
Несколько примечаний к этому ответу: Типичные API-интерфейсы ГИС всегда будут отображать внешнюю сторону многоугольника в порядке против часовой стрелки, IIRC, что означает, что вам не нужно делать это причудливое различение снаружи изнутри - просто используйте вращение по часовой стрелке на внешних кольцах и против часовой стрелки на отверстиях. Пояснение для celenius: бит «набора колец» - это то, как большинство API, включая Python ArcGIS, позволяют вам разбивать многоугольник на составляющие его отрезки - кольцо представляет собой их замкнутую кривую. Поскольку полигоны могут поддерживать острова и дыры, вы можете иметь несколько колец ...
Дэн С.
@ Я бы хотел, чтобы ГИС поддерживали такие согласованные представления. На протяжении многих лет программное обеспечение ESRI колебалось взад и вперед среди отрицательно и положительно ориентированных полигонов и просто оставляло их неориентированными. На данный момент я не уверен, что буду полагаться даже на документально подтвержденные заявления относительно их нынешнего подхода: я буду осторожен. Проверка ориентации стоит мало после того, как вы уже обработали все ребра в кольце.
whuber
... ну, к счастью, я вставил этот небольшой отказ от ответственности IIRC. ;) Не так уж часто я делаю вещи на уровне геометрии в стеке ESRI.
Дан С.
@ Дэн С. - Мне все еще немного неясно, как это можно запрограммировать на python. Есть ли для этого какие-либо рекомендации?
djq
1

Может ли это помочь?

жюльен
источник
Это интересная статья, которую вы выкопали. Однако ни один из описанных там методов не имеет отношения к расчету солнечной экспозиции (если только расчет не является грубым приближением, что, по-видимому, здесь не так).
whuber
1

/ * Может быть, это поможет:

Азимут - pi / 2 - это ориентация наружу сторон многоугольника RHR:

Вот пример PostGIS, вы можете создать таблицу bldg117862, используя оператор в конце. SRID - EPSG 2271 (PA StatePlane North Feet), а геометрия - мультиполигон. Для визуализации в ArcGIS 10 вставьте запрос / подзапросы в соединение уровня запросов с postgis после создания таблицы bldg117862. * /

- === НАЧАЛО ЗАПРОСА ===

/ * Внешний запрос обеспечивает ориентацию внешних ортогональных элементов и создает внешние ортогональные линии, равные по длине линиям сторон от средней точки сторон.

Доминирующим направлением (ями) будет сумма длин, сгруппированных по ориентации в порядке убывания *

ВЫБЕРИТЕ line_id в качестве side_id, длину, градусы (orthoaz) в качестве ориентации, st_makeline (st_setsrid (st_line_interpolate_point (geom, .5), 2271), st_setsrid (st_makepoint (st_x (st_line_interpolate_point (geom, .5))) + (длина * (sin ( orthoaz))), st_y (st_line_interpolate_point (geom, .5)) + (длина * (cos (orthoaz)))), 2271)) как геом из

--next внешний подзапрос создает линии из пар точек сторон, вычисляет азимут (orthoaz) наружу, ортогональный для каждого сегмента

(ВЫБЕРИТЕ bldg2009gid, line_id, st_length (st_makeline (начальная точка, конечная точка)) :: numeric (10,2) как длина, азимут (начальная точка, конечная точка), азимут (начальная точка, конечная точка) - pi () / 2 как orthoaz, st_makeline ( начальная точка, конечная точка) как геом из

/ * самый внутренний подзапрос - используйте generate_series (), чтобы разложить строительные полигоны на пары начальная / конечная точки сторон - note1 - применить правило правой руки для обеспечения общей ориентации всех сторон многоугольника note2 - в примере используется многоугольник, для многоугольника geometryn () могут быть удалены * /

(ВЫБЕРИТЬ generate_series (1, npoints (externalring (geometryn (st_forceRHR (geom), 1))) - 1) как line_id, gid как bldg2009gid, pointn (externalring (geometryn (st_forceRHR (geom), 1))), generate_series (1, npoints (externalring (geometryn (st_forceRHR (geom), 1))) - 1)) в качестве начальной точки, pointn (externalring (geometryn (st_forceRHR (geom), 1)), generate_series (2, npoints (externalring (geometryn (st_forceRHR (geom) ), 1))))) как конечная точка от bldg117862) как t1) как t2

- === КОНЕЦ ЗАПРОСА ===

- операторы создания / вставки таблицы bldg117862

SET STANDARD_CONFORMING_STRINGS TO ON; SELECT DropGeometryColumn ('', 'bldg117862', 'geom'); DROP TABLE "bldg117862"; НАЧАТЬ; CREATE TABLE "bldg117862" (gid serial PRIMARY KEY, "motherpin" varchar (14), "taxpin" varchar (14), "status" varchar (15), "area" числовой, "prev_area" числовой, "pct_change" числовой, «picture» varchar (133), «mappage» varchar (6), «sref_gid» int4, «e_address» varchar (19), «a_address» varchar (19), «perim» числовой, «card» int4, «a_addnum» int4, "e_street" varchar (50), "a_street" varchar (50), "e_hsnum" varchar (10)); SELECT AddGeometryColumn ('', 'bldg117862', 'geom', '2271', 'MULTIPOLYGON', 2); 0106000020DF080000010000000103000020DF080000010000000B0000008C721D6C98AC34415E2C5BB9D3E32541AE56DE17BEAC34410613E5A0A0E325411AB6C794AEAC3441BA392FE372E32541C89C38429DAC3441643857628AE325418C299A9095AC3441F66C29B573E32541983F02087EAC34413080AA9F93E325419BAC3C0A86AC3441AC1F3B3DABE32541803A40B974AC3441E8CF3DB9C2E325413E3758C186AC3441D0AAB0E7F7E325410AAAA5429BAC3441BA971217DCE325418C721D6C98AC34415E2C5BB9D3E32541' ); CREATE INDEX "bldg117862_geom_gist" ON "bldg117862" с использованием gist ("geom" gist_geometry_ops); КОНЕЦ;


источник
0

Предполагая, что ориентация сегментов линии постоянна в многоугольнике, вы можете рассчитать направление (направление) вектора, перпендикулярного каждому сегменту линии. Сейчас у меня нет времени разбираться с кодом, но если вам нужна математика, ее можно легко получить :-)

WolfOdrade
источник