Хранение идентификаторов объектов в строчном виде

Автор Тема: Хранение идентификаторов объектов в строчном виде  (Прочитано 12929 раз)

0 Пользователей и 4 Гостей просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
Добрый день!
Вопрос заключается в необходимости хранить идентификаторы объектов, которые являются вложенными в данный; к примеру -- грани солида (Faces).
Зачем это надо? Объясняю - есть необходимость обрабатывать данные чертежа в другом ПО и вернуть их же + доп. параметры, которые потом назначить этим элементам. В настоящем примере - материалы для граней тела.

У них [дочерних элементов] отсутствует ObjectId, у которого можно было бы получить Handle, а наличествующий SubentityId не имеет нужного представления.
Вариант с генерацией FullSubentityPath https://adn-cis.org/podsvetka-segmenta-polilinii.html тоже не совсем подходит, так как для этого придется создавать дополнительную структуру типа словаря/дерева во время нового перебора граней солидов (во время которого заново находить этот FullSubentityPath, преобразовать в строку и искать по ключу в созданной коллекции). С позиции работы с памятью не очень хорошо .... хоть наверное так пока и поступлю.
Аналогично вместо FullSubentityPath могу использовать "строковый кортеж" типа $"{Solid.Handle}_{Face.Index}".
Также я намеревался использовать в качестве идентификатора грани её центроид (усредненную сумму координат по X,Y,Z) - то есть в целом 3 варианта решения всё равно сводятся к необходимости создания коллекции с сопоставлением ключ:доп. параметры солида, а хотелось бы имея некое строчное представления идентификатора как Handle получать его представление в БД чертежа и производить с ним манипуляции без необходимости сопоставления с чем-либо вспомогательным.

Надеюсь, мысль донёс корректно ....
P.S. Хотя вот что интересно - а этот набор будет упорядочен всегда в рамках текущего состояния солида (не изменяя его) и после перезапуска чертежа (solid_id - это ObjectId солида)
Код - C# [Выбрать]
  1. List < Autodesk.AutoCAD.BoundaryRepresentation.Face > faces = new Brep(new FullSubentityPath(new ObjectId[1] { solid_id }, new SubentityId(SubentityType.Null, IntPtr.Zero))).Faces.ToList();

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Вариант с генерацией FullSubentityPath https://adn-cis.org/podsvetka-segmenta-polilinii.html тоже не совсем подходит, так как для этого придется создавать дополнительную структуру типа словаря/дерева во время нового перебора граней солидов (во время которого заново находить этот FullSubentityPath, преобразовать в строку и искать по ключу в созданной коллекции).
Не понял зачем перебирать грани солида вторично, если ты знаешь Handle этого солида (и соответственно его ObjectId) и номер грани. По этим критериям и создается FullSubentityPath.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
А номер грани это и есть его "номер" в списке Brep.Faces()? Я среди методов не нашел вроде явного номера.
P.S. и да, я чего-то не подумал что перебирать повторно не надо, раз есть явный идентификатор

Отмечено как Решение Georg 01-01-2022, 02:59:29

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А номер грани это и есть его "номер" в списке Brep.Faces()? Я среди методов не нашел вроде явного номера.
P.S. и да, я чего-то не подумал что перебирать повторно не надо, раз есть явный идентификатор
Глянь этот код: https://adn-cis.org/forum/index.php?topic=7169.msg21059#msg21059
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
Да, спасибо, это примерно то и есть!.
Только вот очень расстраивает скорость ... у меня порядка 67000 граней и процесс замены материала/цвета занял аж полчаса выполнения (это делалось в рамках одной транзакции).... ускорить никак невозможно для интереса? (хотя сам понимаю что средств никаких нет ... это так безумно плохо видимо внутренняя сортировка организована в AutoCAD)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
у меня порядка 67000 граней и процесс замены материала/цвета занял аж полчаса выполнения
Нужно смотреть код. Возможно достаточно отключить историю изменений Solid3d и это ускорит процесс (Solid3d.RecordHistory)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
Нужно смотреть код
Ну .... пусть будет так:https://github.com/GeorgGrebenyuk/Civil3D.CustomNodes/blob/a890fe6995f766faba93b313b0b7bc655d549dc8/Code/Main/Solids.cs#L143 . Я делаю методы под Dynamo (сейчас речь идет про пункт 5 ниже)
Логика ниже описана (статью пишу типа параллельно*)

Теперь наметим алгоритм действий:
1. Получаем набор граней тел как коллекцию центроидов (сразу вычисляем центроид как полусумму координат треугольной грани и фиксируем идентификатор каждой грани - родительское тело и порядковый номер в списке граней).
2. Создаем на базе полученных центроидов точки AutoCAD, назначаем им атрибутику в виде ObjectData
3. Экспортируем полученные точки с атрибутикой в SHP-файл;
4. В среде QGIS проводим операцию определения попадания точек в полигоны инструментом Join attributes by location и экспортируем точки с новым атрибутом типа полигона обратно в Civil 3D. При этом заменяем null на другое значение (для территории суши).
5. Загружаем точки mapimport'ом и запускаем второй скрипт, который сперва отсортирует массив точек по спискам (применимо к солиду) и для грани каждого присвоит материал\цвет в зависимости от условия (чтобы не "запрашивать" для произвольной точки свой солид и его внутрянку -- сразу делаем в рамках 1 солида все действия).

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А номер грани это и есть его "номер" в списке Brep.Faces()?
Номер грани это face.SubentityPath.SubentId.IndexPtr
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Georg,
А теперь посмотри на чем происходит основная потеря времени.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
А теперь посмотри на чем происходит основная потеря времени
А как это отлавливать (инструментом)? Я пока не пробовал такое в отношении кода. В отношении программ как-то пользовался Windows Performance Analyzer но тут другое ...

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А теперь посмотри на чем происходит основная потеря времени
А как это отлавливать (инструментом)? Я пока не пробовал такое в отношении кода. В отношении программ как-то пользовался Windows Performance Analyzer но тут другое ...
Не инструментом, а через Windows API.
Вот эта строка мне подозрительна на предмет быстродействия:
Код - C# [Выбрать]
  1. List<Autodesk.AutoCAD.BoundaryRepresentation.Face> solid_faces = brep.Faces.ToList();
Фактически это итерация по всем граням солида, а это имеет смысл только в том случае если ты собираешься менять цвет/материал всем граням, а не только некоторым.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
сли ты собираешься менять цвет/материал всем граням
Всем "поверхностным" вообще-то и собираюсь ... другой вопрос, я так и не понял, как ограничить коллекцию граней только теми, которые относятся к верхней кромке (минуя нижнюю плоскость тела и боковые грани).
Но насчет списка я согласен - заменил это на идентификатор типа 
Код - C# [Выбрать]
  1. string Face_Id = $"{OneSolidId.Handle}_{face.SubentityPath.SubentId.IndexPtr.ToInt64()}";

А инициализирую грань вот так:
Код - C# [Выбрать]
  1. foreach (KeyValuePair<string, string> face_info in faces_info)
  2.                             {
  3.                                 long FaceNumber = Convert.ToInt64(face_info.Key.Split('_')[1]);
  4.                                 IntPtr face_IntPtr = (IntPtr)FaceNumber;
  5.                                 FullSubentityPath path2 = new FullSubentityPath(new ObjectId[1] { OneSolidId }, new SubentityId(SubentityType.Null, face_IntPtr));
  6.                                 using (Brep frep_face = new Brep(path2))
  7.                                 {
  8.                                     Autodesk.AutoCAD.BoundaryRepresentation.Face face = frep_face.Faces.First();

Потом запущу так для интереса ... но тут смущает необходимость программного обращения к этим граням - мб и тут тоже будет тормоза. Я проверял без этого метода - точки сортируются п словарям и прочие действия что на "вход" подаются выполняются до 2 минут.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Georg,
Что-то мне кажется, что вместо:
Код - C# [Выбрать]
  1. FullSubentityPath path2 = new FullSubentityPath(new ObjectId[1] { OneSolidId }, new SubentityId(SubentityType.Null, face_IntPtr));
должно быть:
Код - C# [Выбрать]
  1. FullSubentityPath path2 = new FullSubentityPath(new ObjectId[1] { OneSolidId }, new SubentityId(SubentityType.Face, face_IntPtr));
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
должно быть:
Не совсем правда понимаю где именно это вводить -- на этапе первичной выборки или когда ищу грань по номеру в теле? Во втором случае оно итак грань (по номеру), думаю смысла не будет. А в первом не уверен как это поможет ...

Результаты тестов - если раньше с тем List() выполнялось за 32 минуты, то сейчас  без него с обращением к грани по номеру выходит аж 54 минут. Вообще конечно результаты убивающие, не понимаю почему так медленно. На поверхности из 2100 граней отрабатывает почти мгновенно. Сам файл приложу позже ... авось кто разберется. Так что откатываюсь на момент списка, где хоть как-то работало.

Вообще, так как это тело нельзя экспортировать в IFC (не передается ни цвет ни материал) эта задача мне не нужна ... нет так нет. Интересно больше почему так.
P.S. Взамен можно было бы делать с МПолигонами с нужным цветом по граням тела, а их там уже и как ГИС-примитивы можно передавать со свойством цвета ...

Оффлайн GeorgАвтор темы

  • ADN OPEN
  • **
  • Сообщений: 50
  • Карма: 1
  • //Я не программист
Наконец-то получилась стабильная версия  ;D, не вылетающая и на большом солиде.
https://github.com/GeorgGrebenyuk/Civil3D.CustomNodes/blob/cb422bcff7c0081fa8b9d1735f4fe82d59c3dab1/Code/Main/Solids.cs#L152
Транзакцию перевел в Solid.ObjectId.Open() и тогда вылетать перестало (на моменте tr.Commit()).
Кстати если в методе по назначению материала сделать вместо этого (стабильно работает на этапе получения граней тела для поиска центроида):
Код - C# [Выбрать]
  1. FullSubentityPath path = new FullSubentityPath(new ObjectId[1] { OneSolidId }, new SubentityId(SubentityType.Null, IntPtr.Zero));
вот так:
Код - C# [Выбрать]
  1. FullSubentityPath path = new FullSubentityPath(new ObjectId[1] { OneSolidId }, new SubentityId(SubentityType.Face, IntPtr.Zero));
То выбьется такое исключение.

По скорости вообще не заметил особо преимущества, что с ним что без него.
Отмечу как решение тот ваш пост, так как по сути в нём и ответ - оборачивание метода в Open без транзакции и получение идентификатора грани солида.


P.S. Ищу тег материала, как запрос ключа словаря строки типа "Solid.Handle_Face.Id"
Более подробно всю методику расписал в статье.
https://zen.yandex.ru/media/id/5d0dba97ecd5cf00afaf2938/autocad-3d-api-i-osm-naznachaem-materialy-graniam-3dtel-61cd4b2205c49671f55b07af

Не инструментом, а через Windows API.
P.P.S. Буду также благодарен за направление где посмотреть примеры такой отладки ... а то в процессе настройки текущих он вылетал вообще без каких-либо Exception