Найти в Дзене
Хроники Георга

Занимательное Dynamo. Получение геометрии примитивов AutoCAD, Object Data и экспорт в GeoJSON

Оглавление

Введение: в данной статье мы продолжим серию статей по работе с Dynamo в среде Civil 3D, и рассмотрим работу с примитивами AutoCAD имеющими поля Object Data и преобразование их в GeoJSON (один из открытых ГИС-форматов данных) через Python-скрипты в Dynamo.

Снова та же картинка (Оригинал: https://avatars.mds.yandex.net/get-zen_doc/198359/pub_5b031feb83090562e4b1650f_5b0e832057906a66d8e239bb/scale_1200)
Снова та же картинка (Оригинал: https://avatars.mds.yandex.net/get-zen_doc/198359/pub_5b031feb83090562e4b1650f_5b0e832057906a66d8e239bb/scale_1200)

1. О чем будем говорить?

В ранней статье по загрузке данных в мобильное приложение NextGIS Mobile для анализа проектных решений на местности мы рассматривали по большей части примитивы AutoCAD (полилинии и 3D-грани, которые передавали через SHP в NextGIS Web для последующей загрузки в NextGIS Mobile). Существует и альтернативный вариант загрузки "своих" данных - в виде GeoJSON-файлов (если не приобретать подписку). К сожалению, напрямую они в Civil 3D не формируются, поэтому необходимо преобразовывать геометрию объектов в промежуточный формат, например, SHP и уже его преобразовывать в GeoJSON используя QGIS (как десктопный вариант), либо консольный OSGeo4W:

ogr2ogr -f GeoJSON -t_srs crs:84 PathToFileFinish.geojson PathToFileSource.shp

Поэтому, в настоящей статье мы рассмотрим процесс получения геометрии примитивов AutoCAD (полигоны) вместе с набором атрибутов из Object Data (вариант с Наборами Характеристик мы рассмотрим в другой статье) и преобразование информации в GeoJSON-файл. Извлечение геометрии напрямую из объектов Civil 3D мы также рассмотрим в рамках другой статьи - чтобы не усложнять данную.

В силу того, что работа с полигонами встречается крайне редко, мы интерпретируем полигоны как замкнутые полилинии.

2. Исходные файлы

Исходные файлы я выкладываю по данной ссылке.

В качестве исходных данных я возьму набор участков и преобразую их в полигоны со свойствами (ObjectData) руководствуясь методикой данной статьи.

Рабочий исходный файл
Рабочий исходный файл
Активируем опцию экспорта в SDF
Активируем опцию экспорта в SDF
Сохраняем
Сохраняем
В новом чертеже активируем опцию MAPIMPORT
В новом чертеже активируем опцию MAPIMPORT
Оставляем объекты = участки, настраиваем набор атрибутов - ObkectData и ставим галочку "импортировать полигоны как замкнутые полилинии"
Оставляем объекты = участки, настраиваем набор атрибутов - ObkectData и ставим галочку "импортировать полигоны как замкнутые полилинии"
Результат - набор замкнутых полилиний с атрибутикой
Результат - набор замкнутых полилиний с атрибутикой

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

2.1 Корректируем геометрию полилиний

Важный момент, о котором стоит упомянуть - это формат замкнутой полилинии (в силу того, что она "вырождена" из полигона, в её структуре присутствует точка, где накладываются 2 точки, и на этом впоследствии возникнут проблемы при обработке геометрии полилинии). Устраним это при помощи операции функционала MAPCLEAN "Упростить полилинии"

Примечание: об этом способе решения проблемы подсказал Максим Козлов из чата Dynamo for Civil 3D (ссылка).

Запускаем окно MAPCLEAN
Запускаем окно MAPCLEAN
Выбираем опцию оптимизации геометрии (параметр "Расстояние в м.)
Выбираем опцию оптимизации геометрии (параметр "Расстояние в м.)
Ничего не трогаем
Ничего не трогаем
Результат операции в командной стоке - удалены 12 объектов для 12 выбранных полилиний
Результат операции в командной стоке - удалены 12 объектов для 12 выбранных полилиний

3. Определяемся со структурой скрипта и используемыми нодами

Нам необходимо получить геометрию и набор атрибутов, представленный полями Object Data для ряда объектов (Полилинии) и преобразовать их в GeoJSON. Преобразование в GeoJSON будем делать с помощью словарей (Dictionary) через Python-нод. Сама спецификация к слову выглядит примерно так.

Примечание: безусловно, есть, возможно, более "правильные" способы записи в JSON, но я ограничусь своим вариантом.

Финальный вид скрипта (начнем с того, что получится)
Финальный вид скрипта (начнем с того, что получится)

Итак, начнем анализировать структуру скрипта (см. картинку выше):

3.1 Получение геометрии и свойств (атрибутики)

Нодом Select Objects мы выбираем группу участков (N = 13 штук).

Выбор объектов (всё понятно)
Выбор объектов (всё понятно)

Розовая группа нодов - это получение информации по таблицам с ObjectData и значением параметров ObjectData для выбранной группы объектов (каждой полилинии). Итог работы группы нодов - это возврат списка List из N-словарей (объект типа Dictionary). Здесь используются ноды из пакета Civil3DToolkit.

Получение всех словарей с ObjectData по каждому из объектов
Получение всех словарей с ObjectData по каждому из объектов

Зеленая группа нодов - это получение геометрии каждого сегмента полилинии в рамках каждой полилинии (отдельного списка List).

Получение геометрии полилиний
Получение геометрии полилиний

3.2 Вспомогательные ноды

К числу вспомогательных нодов, необходимых для будущего Python-скрипта я отнес следующие элементы:

Во-первых, я создал генератор уникальных имен файлов на базе GUID (UUID), для чего получил абсолютный файловый путь к текущему DWG-файлу, заменил ему расширение на .geojson и добавил упомянутый UUID в имя файла.

Получение уникального имени файла
Получение уникального имени файла

Во-вторых, нам понадобится знать, какая система координат назначена чертежа (так как записывать мы будем пространственные данные). Если речь идет об отечественных СК, у них кода EPSG нет, и необходимо из них (из этого чертежа) перевести данные в другую СК, для которой код EPSG есть (к примеру, одну из зон UTM84 либо проекцию Гаусса-Крюгера). В нашем случае, можно задать ее как строку или воспользоваться нодом CoordinateSystems.GetEPSGForCurrentCS из моего пакета Dynamo.MapConnection.

Получение EPSG кода для СК чертежа
Получение EPSG кода для СК чертежа

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

Выбор типа "линия"/"полигон"
Выбор типа "линия"/"полигон"

4. Пишем Python-скрипт

Сразу оговорюсь, что демо-материалы доступны по ссылке (рабочий файл DWG и используемый скрипт).

Так как работать мы будем в большей степени со словарями, рекомендую прочесть предварительно о них материал у Вадима Муратова в этой статье и емкую справку на Metanit.

Структура входных данных и результата работы скрипта
Структура входных данных и результата работы скрипта

В моем случае, Python Script обрабатывает входные данные и формирует словарь (Dictionary) со структурой файла GeoJson (для проверки структуры я сформировал его "классическим" способом через QGIS и далее писал с натуры с него).

Мой вспомогательный "опорный" файл
Мой вспомогательный "опорный" файл
Начальная часть (подключение библиотек и инициализация входных данных)
Начальная часть (подключение библиотек и инициализация входных данных)

Здесь мы подключаем вспомогательную библиотеку ProtoGeometry для свойств объекта типа Curve и Point.

Вспомогательная функция для возвращения координат точки как списка
Вспомогательная функция для возвращения координат точки как списка

Примечание: мы намеренно не используем оригинальные типы данных, а сводим их к стандартным (строковым/числовым), так как в противном случае на этапе формирования JSON-структуры мы получим ошибки типизации.

Первая рабочая часть скрипта
Первая рабочая часть скрипта

Здесь мы инициализируем словарь Dict_Root, в значение "features" которого мы по завершению перебора входных значений положим набор информации (пока что его величина = 0).

Внутреннее содержимое группы "features" представляет собой список, поэтому мы создали переменную Dict_AllFeatires с такой структурой.

Далее мы начали перебирать словарь с ObjectData, формируя также словарь для этого объекта - Dict_OneParcel, у которого временно указываем пустые значения для "properties" и "geometry".

Получаем информацию по свойствам из ObjectData
Получаем информацию по свойствам из ObjectData

Теперь перебираем ключи и значения из входного словаря и формируем временный элемент Dict_ParcelProperties, который добавляем по ключу "properties" в словарь для элемента участка Dict_OneParcel.

Работа с геометрией
Работа с геометрией

Теперь используя индекс Counter1 (при переборе словаря с атрибутикой ObjectData) обращаемся к аналогичному списку, но уже с элементами геометрии.

Здесь у нас немного громоздкая структура, связанная с необходимостью проверки параметра CreatePolygonOption (делать/не делать полигоны из полилиний). В рамках цикла for мы пробегаемся по всем вершинам полилинии и преобразуем их в строкое представление с помощью нашей вспомогательной функции GetCoordAsStringfromPoint () из объекта Geometry.Point.

После формирования списка Dict_Geometry добавляем его по ключу "geometry" в Dict_OneParcel. Увеличивая счетчик Counter1+=1, переходим к следующему участку и добавляем данный словарь в Dict_AllFeatires.

Завершение скрипта
Завершение скрипта

На завершении мы возвращаем список из словарей в "features" и возвращаем из скрипта словарь Dict_Root.

Сохранение данных
Сохранение данных

Для сохранения словаря в JSON-представление мы пользуемся вспомогательным нодом из стандартной поставки Dynamo - Data.StringifyJSON, который подаем как строку на вход стандартного нода записи в файл (в качестве Имени файла используем наше уникальное значение).

На этом, собственно и всё :)

5. Заключение

В данной статье мы копнули глубже в работу с Dynamo, затронув тему работы с геометрией примитивов AutoCAD (замкнутые полилинии) и атрибутикой в формате ObjectData.

В процессе обработки данных активно использовали словари и списки в Python для формирования JSON-файла.

В следующей статье я постараюсь рассмотреть работу с объектами Civil 3D (трассы, характерные линии и COGO-точки).

Далее я продолжу писать в таком же ключе; буду благодарен за идеи, примеры реализации чего рассмотреть - пишите об этом в комментариях, либо в telegram-группе Dynamo for Civil 3D.

#autodesk #dynamo #ironpython #pyton #civil 3d #autocad #bim #script #python script #dynamo for civil 3d

Не пропускайте публикации, подписывайтесь на Telegram-канал с тизерами статей.