Хотелось бы выполнять операцию более быстро, минуя промежуточные шаги с использованием Solid3D. Есть ли более быстрый способ сделать это средствами API AutoCAD?У класса Region есть метод BooleanOperation, который теоретически может помочь. Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного региона, выполнить пересечение (BoolIntersect) исходного Region с эталонным.
Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного регионаМожет не сдвигать, а сразу прямоугольный массив создать?
Может не сдвигать, а сразу прямоугольный массив создать?Думаю что тут будут большие расходы по памяти если достаточно большой исходный регион.
Не уверен, что этот способ будет более быстрым, но попробовать можешь.Я думаю производительность алгоритмов в данном случае будет зависеть от исходных данных (то есть будут случаи когда выигрывает один на одних исходных данных, и проигрывает на других) - в общем смотреть что ближе к "среднестатистическому использованию".
У класса Region есть метод BooleanOperation, который теоретически может помочь. Т.е. можно создать эталонный Region размером [dx dy] и, сдвигая его по сетке в границах исходного региона, выполнить пересечение (BoolIntersect) исходного Region с эталонным.Так и сделал. Прироста производительности по сравнению с этим (http://adn-cis.org/forum/index.php?topic=495.msg1538#msg1538) не наблюдаю (примерно то на то и выходит по времени), однако есть и положительный момент: корректно обрабатываются регионы, выполненные сплайнами.
Не уверен, что этот способ будет более быстрым, но попробовать можешь.
Тут возможна еще оптимизация при помощи Brep, если границы эталонного Region находятся внутри исходного Region и не пересекают его, то результирующий Region равен эталонному, а если пересечения границ нет вообще, то эталонный Region вне исходного.Завтра добавлю эту оптимизацию. Надеюсь, что после этого скорость работы всё же увеличится.
В качестве дополнительной оптимизации попробую распараллелить все манипуляции с регионами по разным потокам. Исхожу из того, что весь процесс происходит без привлечения Database и Application;Так как все объекты из пространства имён Autodesk.AutoCAD.DatabaseServices есть ни что иное как обертки над ObjectARX классами AcDb из библиотеки acdbxx.dll, которая в свою очередь не является потокобезопасной, я бы поостерегся это делать. Во всяком случае рекомендую оставить этот вид оптимизации на потом.
обертки над ObjectARX классами AcDb из библиотеки acdbxx.dll, которая в свою очередь не является потокобезопасной, я бы поостерегся это делать.Ок, спасибо, пожалуй откажусь от этой идеи.
Как оказалось, данная оптимизация оказалась невозможной, т.к. в ряде случаев приводит к некорректным результатам проверки.ЦитироватьТут возможна еще оптимизация при помощи Brep, если границы эталонного Region находятся внутри исходного Region и не пересекают его, то результирующий Region равен эталонному, а если пересечения границ нет вообще, то эталонный Region вне исходного.
Завтра добавлю эту оптимизацию. Надеюсь, что после этого скорость работы всё же увеличится.
В ADN DevHelp подтвердили багА ведь помнится вы утверждали, что в Autodesk тестируют код... Ну и как же они его тестируют, когда обозначенный функционал не работает ни в 2009-м, ни в 2015-м? Что-то мне подсказывает, что все промежуточные версии покажут тот же результат.
А ведь помнится вы утверждали, что в Autodesk тестируют код...Это у тебя склероз проявляется. ;) Я утверждал, что тестируют сам AutoCAD, но не код. Код тестируется (как я понимаю) тот, который они сами используют. Так вот им видимо в голову не пришло использовать managed код для BREP - только native. IMHO.
Код тестируется (как я понимаю) тот, который они сами используют.Тогда удивляться не приходится.
вот "нарезал" из своих кусков:Спасибо, правда для меня F# как китайская азбука.
Реализованна как лисп функция формат вызова (narez <ename> ширина_сегмента высота_сегмента); проверь идет ли с твоими тестовыми образцами и быстрее-ли.Очень неудобны следующие моменты:
Скомпилированную для 2014 прикладываю.
попробуй регенерацию.
(выполнен regen)
(выполнен regen)Проскочил - скорее всего это визуализация проблемы точности вычисления float числа (типа так какой-нибудь синус посчитал)...
Error 11 Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration.
Command: NAREZОднако при использовании твоего кода на больших объемах исходных данных, как правило, получаю проблему:
Select objects: 1 found
Select objects:
РЁРёСЂРёРЅР° 10
Высота 10
Затраченное время: 00:00:00.7099610
nil
Command:
Command: MESHREGIONS
Выберите области (Regions) для добавления их в набор: 1 found
Выберите области (Regions) для добавления их в набор:
Всего выбрано областей (Regions): 1
dx <10>:
dy <10>:
Создано областей (region): 160
Затраченное время: 00:00:00.8574218
Command: NAREZ
Select objects: 1 found
Select objects:
РЁРёСЂРёРЅР° 10
Высота 10
Затраченное время: 00:00:00.7148438
nil
Command:
Command: MESHREGIONS
Выберите области (Regions) для добавления их в набор: 1 found
Выберите области (Regions) для добавления их в набор:
Всего выбрано областей (Regions): 1
dx <10>:
dy <10>:
Создано областей (region): 158
Затраченное время: 00:00:00.8476563
Command: NAREZ
Select objects: 1 found
Select objects:
РЁРёСЂРёРЅР° 10
Высота 10
Затраченное время: 00:00:00.5317500
nil
Command:
Command: MESHREGIONS
Выберите области (Regions) для добавления их в набор: 1 found
Выберите области (Regions) для добавления их в набор:
Всего выбрано областей (Regions): 1
dx <10>:
dy <10>:
Создано областей (region): 132
Затраченное время: 00:00:00.7197266
Command: NAREZ
Select objects: 1 found
Select objects:
РЁРёСЂРёРЅР° 10
Высота 10 Затраченное время: 00:01:05.3681641
nil
Command:
Command: MESHREGIONS
Выберите области (Regions) для добавления их в набор: 1 found
Выберите области (Regions) для добавления их в набор:
Всего выбрано областей (Regions): 1
dx <10>:
dy <10>:
Создано областей (region): 38865
Затраченное время: 00:02:16.3663656
---------------------------с последующим Fatal Error. Зачастую это происходит при первом автоматическом сохранении чертежа, в котором нарезкой уже создано огромное количество регионов. Полагаю, что у тебя происходит утечка памяти (например не все нужные Dispose вызываешь).
AutoCAD Error Aborting
---------------------------
FATAL ERROR: Out of memory - shutting down
---------------------------
ОК
---------------------------
В привычном варианте установи библиотеки и добавь1-ю строку типа module narezВ строке
(rg,Intersect.ExtendThis,pc,0n,0n)
получаю исключение:Error 11 This expression was expected to have type
int
but here has type
nativeint
В строкеУбрал суффиксы "n" - всё скомпилировалось. Однако в свете обозначенной выше проблемы с утечкой памяти, пока откладываю в сторону.Код: [Выделить](rg,Intersect.ExtendThis,pc,0n,0n)
получаю исключение:ЦитироватьError 11 This expression was expected to have type
int
but here has type
nativeint
заниматься Intersect'ом не на каждой итерации - а анализируя геометрию прохождения границ (строки 55-65):можешь перевести эти строки на C#, чтобы я смог их прочесть?
Убрал суффиксы "n" - всё скомпилировалось.По моему там чуть разные перегрузки метода в различных версиях автокада (под 2014 компилировал точно как в примере).
Про утечку - посмотрю - приложи dwg файлик.Тестировал на этом (http://adn-cis.org/forum/index.php?action=dlattach;topic=495.0;attach=223) файле, предварительно скопировав содержимое два раза и затем всё это отправив в обработку (нарезку). Windows 7x86.
"шаг резьбы"?10х10
Я же писал о минимальной относительной погрешности в 1e-6. Вот похоже она и вылезла.1. Это проявляется даже если левый нижний угол границы региона находится в центре WCS.
1. Это проявляется даже если левый нижний угол границы региона находится в центре WCS.Здесь это уже не принципиально.
2. Код, написанный Дима_ не даёт таких погрешностей на тех же самых исходных регионах.Дима сразу вырезает ячейки-прямоугольники размером [dx,dy], а ты сначала режешь строками, а потом их уже делишь на ячейки. Наверное разница в этом.
Дима сразу вырезает ячейки-прямоугольники размером [dx,dy], а ты сначала режешь строками, а потом их уже делишь на ячейки. Наверное разница в этом.А по другому никак: иначе я буду получать неправильные результаты, что и происходит в ряде случаев с использованием кода Дима_. Ниже прилагается дополнительный чертёж с тестовыми регионами. Берём первый "Ш"-образный регион и вызываем команду NAREZ, указывая следующие параметры:
Command: NAREZНа выходе визуально всё вроде выглядит правильно, однако это не так: выделяем верхний левый кусок и видим, что выделилась вся "строка". Возможно для Дима_ такой результат является именно тем, что нужно, однако моим пользователям для каждого из нарезанных кусков нужно получать центр масс. Соответственно в данном случае будет показан центр масс, общий для трёх кусков, а это не то, что требовалось моим юзерам. Именно поэтому у меня в коде две итерации: сначала строки, затем колонки. Собственно эти нюансы я и показывал здесь (http://bushman-andrey.blogspot.ru/2014/05/regions.html), выполняя различные логические операции над регионами.
Select objects: 1 found
Select objects:
РЁРёСЂРёРЅР° 135
Высота 20
Затраченное время: 00:00:00.0595703
nil
Я же писал о минимальной относительной погрешности в 1e-6. Вот похоже она и вылезла.Нет, это однозначно ошибка в моём коде. Завтра буду искать. Скорее всего где-то сделал Ctrl+C, Ctrl + V и не переименовал переменную (ну, или что-то вроде того).
По фаталу - да действительно если создать значительное кол-во сегментов - то автокад намертво зависает на записи (у меня x64) - либо я просто не дождался завершения, причем висит именно на записи, саму "нарезку" он делает, я попробовал еще включать dispose копиям "главных" объектов которые идут как аргумент в BooleanOperation (что по моему представлению должно быть встроено непосредственно в метод) - результата не дало. Можно просто попробывать создать эквивалентное кол-во регионов - может просто акад "не осиливает", т.к. вроде все созданное либо в БД либо в Dispose.В режиме DEBUG загляни в отладочную консоль. Если у тебя где-то пропущен вызов Dispose, то там должна появиться подсказка на эту тему, т.к. реализация метода !DBObject() следующая:
По "проблеме буквы Ш" - чтобы "уши" буквы были в разных областях - надо задавать соответствующие размеры "клетки", я не очень понимаю как от этого спасает алгоритм "нарезать вначале строки, потом столбцы", да строки немного "запляшут"Да, что-то меня перемкнуло: твой код запустил, чтобы проверить проблему, а свой почему-то решил не запускать, т.к. "всё должно быть пучком". Похоже я поторопился, завтра ещё подумаю. Проблема в том, что нужно как-то гарантированно резать так, чтобы в одном регионе не было нескольких сегментов (как при резке буквы Ш клеткой, равной длине региона).
то и его нужно отдельно обрабатывать и т.д. рекурсивно анализируя структуру контуров...... это не слабое такое уточнение...
... это не слабое такое уточнение...Согласен. Просто когда я показал юзеру эту ситуацию на конкретных примерах, и уточнил насчёт рекурсивного анализа (островки в отверстиях и т.п.), то ответ был "ну конечно же, это обязательно".
короче по хорошему сложно (очень), по "быстрому" не быстро и "криво".Буду пытаться найти "консенсус" с юзерами.
боюсь через текущий .Net API тут глухоДля этого есть BREP .NET API
Буду пытаться найти "консенсус" с юзерами.ИХМО - по моему, в данном случае, это наиболее верное решение.
Про Brep Вы же сами здесь писали - что не прокатит?Там ошибка в одном из методов, который к этой теме отношения не имеет. Да и тот метод можно реализовать через P/Invoke.
Маэстро! раз и Вы не спите - на что похожи "симптомы" когда много (очень) объектов создано, но потом не сохранится? (Dispose пропущен или еще что).Вполне возможно, что пропущен Dispose. Но на 100% уверенно сказать не могу. Особенно в AutoCAD 2014, в котором переписали работу с Solid3d и Region таким образом, что быстродействие упало при прочих равных условиях в два раза по сравнению с AutoCAD 2013 (факт подтвержденный в ADN DevHelp).
Особенно в AutoCAD 2014, в котором переписали работу с Solid3d и Region таким образом, что быстродействие упало при прочих равных условиях в два раза по сравнению с AutoCAD 2013 (факт подтвержденный в ADN DevHelp).А в 2015-м как дела обстоят?
А в 2015-м как дела обстоят?Пока также как и в 2015 - я слишком поздно отправил этот баг.
Нет, это однозначно ошибка в моём коде. Завтра буду искать. Скорее всего где-то сделал Ctrl+C, Ctrl + V и не переименовал переменную (ну, или что-то вроде того).Нашёл ошибку: при рассечении на "столбцы" габариты расчитывались относительно региона "строки". А поскольку в ряде случаев строка может содержать в составе контура куски сплайнов, то и габариты показываются не те, что видны визуально (по понятным причинам). Внёс исправление - все смещения dx, dy выполняю относительно габаритов базового региона. Заодно и сетка ровная получается. Сейчас добавлю некоторые дополнительные изменения. Посмотрю, что быстрее: клонировать и смещать регион, или же создавать новый на основе вычисленных точек и контура.
Можно попробовать это исправить отключив запись UNDO при помощи вызова Database.DisableUndoRecording(true);Это первое про что я подумал и в dll и в лиспе - но не оно.
з.з.ы. Сейчас автор в соседней теме найдет как считать наиболее "правильные" границы через brep, и можно будет еще разогнать на "сплайновых" областях - хотя и "пустые" участки алгоритм пробегает достаточно быстро (без булевых операций с регионами), но все равно делать их незачем.Угу. Найдено и было показано здесь (http://adn-cis.org/forum/index.php?topic=495.msg2970#msg2970) ещё в 14:28. Обновил здесь (http://bushman-andrey.blogspot.ru/2014/05/regions_29.html) описание, скрины и код. Осталось решить проблему объединённых регионов. Но это уже не сегодня. Завтра заодно оптимизирую код GetVisualBoundary, чтобы половинить расстояния, те опять половинить и т.д. а не приращать на значения dx и dy (а то текущий вариант похож на пузырьковую сортировку :)).
проще говоря если регион из двух кусков, можно запросто попасть между ними - в общем есть вариант оставить "как есть".Хм... Как вариант, можно с помощью Brep попробовать проанализировать границы каждого Face и вычислить для них (minX, minY) и (maxX, maxY).
пока вижу только вариант брать заведомо меньший размер клеткиТут видишь ли в чём дело... Проектировщикам нужно сечение конструкции в разных местах кромсать по разному. Т.е. они сначала могут дать команду разрезать регион на три строки (не рассекая их на столбцы), а затем к каждой строке применить свою собственную команду нарезки со своим размером ячейки. Как правило, крайние строки им нужно резать на как можно меньшие ячейки, в то время как строки ближе к центру можно резать на бОльшие куски.
Хм... Как вариант, можно с помощью Brep попробовать проанализировать границы каждого Face и вычислить для них (minX, minY) и (maxX, maxY)."Я эту идею породил - я её и убью". Она будет несправедлива в случае если внутренние контура могут быть не выпуклыми.
Она будет несправедлива в случае если внутренние контура не выпуклые.Поясните. Какая разница "выпуклые" или "впуклые"? Границы-то один хрен: двумя точками кажет (левый нижний и правый верхний).
Поясните. Какая разница "выпуклые" или "впуклые"? Границы-то один хрен: двумя точками кажет (левый нижний и правый верхний).Подумай как будут выглядеть окаймляющие прямоугольники у этих двух фигур и как они будут располагаться один относительно другого:
Вот если бы можно было на основе Face создать Region, то тогда проблема бы отвалилась.Ну в принципе можно. Только не на основе Face, а на основе Loop ты должен создавать Region. Фактически в указанном тобой "неправильном" Region вместо одного несколько Loop. Каждый Loop состоит из одной или нескольких Edge, которую можно превратить в Curve3d. Из Curve3d можно получить (с заданной точностью) набор точек, которые её представляют. Как это сделать я показал тут: http://adn-cis.org/forum/index.php?topic=495.msg2990#msg2990
Те, что видели на тему триангуляции, строят треугольные объекты Face (это годится) по точкам, и не учитывают отверстия (а это уже не то...)Вот эта библиотека (http://triangle.codeplex.com/) делает триангуляцию по точкам, при этом есть возможность указать отверстия и контуры.. недавно с ней пришлось основательно поиграться..
Если мы взрываем объединённые регионы, то при первом взрыве мы получаем набор отдельных регионов,Ну это просто сказачное везение - тогда проблемма буквы Ш решаеться 5-тью строками, но предложенная мной оптимизация идет лесом - т.к. "островок" может попастся внутри клетки и пересечения не будет - то есть каждую клетку надо "булеанить", а потом еще и проверить brepom - в общем процесс будет совсем не быстрый...
то есть каждую клетку надо "булеанить", а потом еще и проверить brepom - в общем процесс будет совсем не быстрый...Именно так я и делаю. Пользователя скорость устраивает, по его заявлению, т.к. написанный им вариант на VBA работал ещё медленнее.
или там 1-го взрыва всегда достаточно?
2. Если мы взрываем объединённые регионы, то при первом взрыве мы получаем набор отдельных регионов, с сохранением отверстий (если таковые имеются). Повторный взрыв делает то же самое, что и в п.1.рекурсивный взрыв не требуется, всё "как надо" после первого взрыва.
Перед тем как делать ниженаписанное вначале надо ответить на главный вопрос "Надо-ли"На данный момент не надо.
Т.о. если я вижу, что Face Complexes более 1, то взрываю регион и полученные новые регионы добавляю в набор. Проверил, работает.Отлично. Если это всегда так, то совсем замечательно. Можно например написать свой вариант команды EXPLODE, которая расчленяет только Region/Solid3d, но только тогда, когда они состоят из отдельных частей и расчленяются на составляющие Region/Solid3d.
т.к. написанный им вариант на VBA работал ещё медленнее.Уповать на скорость API против алгоритма никогда не стоит - рано или поздно тыкнут носом - вот мол на такой ...не пишут, а работает в Х-раз быстрее, а ты тут извращаешся, а результату...
Уповать на скорость API против алгоритма никогда не стоитЯ никогда и не полагаюсь на это. Похоже, что ты меня неверно понял.
Пользователя скорость устраивает, по его заявлению, т.к. написанный им вариант на VBA работал ещё медленнее.Эта фраза означает, что пользователь предварительно написал свой вариант реализации, используя для этого язык VBA и конечный результат работал медленней моего. Язык программирования, используемый пользователем, был мною указан лишь в качестве дополнительной информации. Я не вкладывал в это предложение смысл, мол "у юзера медленней, потому что он пишет на VBA". Алгоритм реализации у пользователя был свой: половинить до тех пор, пока очередная половина не станет меньше либо равной обозначенным dx и dy.
в итоге получилось побыстрее чем предыдущая версия (без стойкости к букве Ш).Как я уже писал выше корректная обработка "Ш" и ей подобных ситуаций - обязательное требование проектировщиков. В виду этого выбираю алгоритм менее быстрый, но дающий именно те результаты, которые от него ожидают во всех (а не "почти во всех") возможных ситуациях (во всяком случае в тех, которые я использовал в ходе тестирования).
Я тут приболелТы это дело брось! :)
Как я уже писал выше корректная обработка "Ш" и ей подобных ситуацийВобщем опять не там запятая - этот как раз и устойчивый к букве Ш (собсвеннно из-за чего и пришлось проверку пересечения заменить индексацией) - то есть корректно обработает.
Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.Region): DisposableWrapperПоскольку в твоём варианте нет возможности указать значение delta, то мне не удаётся проверить твой код на тех же условиях, когда вариант А.Н. выдавал исключение для delta = 0.1.
Вобщем опять не там запятая - этот как раз и устойчивый к букве Ш (собсвеннно из-за чего и пришлось проверку пересечения заменить индексацией) - то есть корректно обработает.Да, "Ш" обрабатывается корректно и в целом всё работает весьма шустро. Я через ILSpy конвертну твой код в C#, дабы посмотреть алгоритм.
Не... результат декомпиляции ILSpy таков, что это мне будет нужно не один день потратитьНу этого стоило ожидать т.к. по сути тебе ковырять F# библиотеку придется (а она как не крути лучше исходника не станет) + то что в обобщенных методах было она в свои несколько перевела. Алгоритм если надо могу расписать.
Алгоритм если надо могу расписать.Буду признателен. При этом хочу обратить внимание на "корректную расстановку запятых", т.к. порой мне либо сложно понять то, что ты пишешь, либо понимаю неверно.
С "диспозами" разобрался, но если меня не перемыкает в других версиях автокада такой диспоз (объекта который будут интерсектить вел к фаталу)Я могу запустить твой код в AutoCAD версий 2009-2015. Могу попробовать, если обозначишь нужную версию. Погоди, а ты что, сейчас где-то диспозишь объект, который потом интерсектишь? :)
Мне казалось, что раньше, объект который передавался в BooleanOperation как аргумент автоматом диспозился этим-же методом (что по логике правильно т.к. его фактически уничтожает), а может и глюк.Нет. Это тебе только казалось. Его нужно уничтожать самому. Он становится IsNull (что означает что он "пустой", т.е. не имеет геометрии), но не уничтожается.