Введение: в данной статье мы продолжим серию статей по работе с Dynamo в среде Civil 3D, и рассмотрим работу с примитивами AutoCAD имеющими поля Object Data и преобразование их в GeoJSON (один из открытых ГИС-форматов данных) через Python-скрипты в Dynamo.
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) руководствуясь методикой данной статьи.
Примечание: в рамках текущей статьи мы рассмотрим работу именно с геометрией замкнутых полилиний (по факту, обычных полилиний) ввиду того, что работа с полигонами , во первых, встречается редко, а во вторых - так просто к их геометрии не подобраться с программной точки зрения.
2.1 Корректируем геометрию полилиний
Важный момент, о котором стоит упомянуть - это формат замкнутой полилинии (в силу того, что она "вырождена" из полигона, в её структуре присутствует точка, где накладываются 2 точки, и на этом впоследствии возникнут проблемы при обработке геометрии полилинии). Устраним это при помощи операции функционала MAPCLEAN "Упростить полилинии"
Примечание: об этом способе решения проблемы подсказал Максим Козлов из чата Dynamo for Civil 3D (ссылка).
3. Определяемся со структурой скрипта и используемыми нодами
Нам необходимо получить геометрию и набор атрибутов, представленный полями Object Data для ряда объектов (Полилинии) и преобразовать их в GeoJSON. Преобразование в GeoJSON будем делать с помощью словарей (Dictionary) через Python-нод. Сама спецификация к слову выглядит примерно так.
Примечание: безусловно, есть, возможно, более "правильные" способы записи в JSON, но я ограничусь своим вариантом.
Итак, начнем анализировать структуру скрипта (см. картинку выше):
3.1 Получение геометрии и свойств (атрибутики)
Нодом Select Objects мы выбираем группу участков (N = 13 штук).
Розовая группа нодов - это получение информации по таблицам с ObjectData и значением параметров ObjectData для выбранной группы объектов (каждой полилинии). Итог работы группы нодов - это возврат списка List из N-словарей (объект типа Dictionary). Здесь используются ноды из пакета Civil3DToolkit.
Зеленая группа нодов - это получение геометрии каждого сегмента полилинии в рамках каждой полилинии (отдельного списка List).
3.2 Вспомогательные ноды
К числу вспомогательных нодов, необходимых для будущего Python-скрипта я отнес следующие элементы:
Во-первых, я создал генератор уникальных имен файлов на базе GUID (UUID), для чего получил абсолютный файловый путь к текущему DWG-файлу, заменил ему расширение на .geojson и добавил упомянутый UUID в имя файла.
Во-вторых, нам понадобится знать, какая система координат назначена чертежа (так как записывать мы будем пространственные данные). Если речь идет об отечественных СК, у них кода EPSG нет, и необходимо из них (из этого чертежа) перевести данные в другую СК, для которой код EPSG есть (к примеру, одну из зон UTM84 либо проекцию Гаусса-Крюгера). В нашем случае, можно задать ее как строку или воспользоваться нодом CoordinateSystems.GetEPSGForCurrentCS из моего пакета Dynamo.MapConnection.
В третьих, я даю возможность выбрать, геометрия какого типа будет формироваться (линии/полигоны) при условии, если в чертеже полилинии замкнуты. В противном случае скрипт необходимо будет дополнить операцией проверки замкнутости полилинии.
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".
Теперь перебираем ключи и значения из входного словаря и формируем временный элемент 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