Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Александр Пекшев aka Modis от 03-04-2016, 23:35:27

Название: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 03-04-2016, 23:35:27
Всем привет! Эта проблема не дает мне покоя уже оооочень много времени!
Иногда пишет просто фатальную ошибку, иногда - недостаточно памяти
Основных загвоздок две:
1. Ошибка происходит во время Jig, поэтому не могу использовать отладку
2. (ВАЖНО) Ошибка происходит только в некоторых файлах! Причем, чем они отличаются от других - так сразу и не поймешь

Краткие действия функции:
1. Из файла на жестком диске копируется таблица в текущий чертеж
2. Пользователь указывает точку и таблица туда перемещается
В общем - банальная вставка таблицы
После долгих мучений и всяческих переделок я добавил в функцию возможность отключения динамической отрисовки таблицы на курсоре. Иными словами - без использования Jig. В этом случае - проблем не наблюдается
Сам метод примерно такой:
Код - C# [Выбрать]
  1. private void InsertTable(string pointAligin, ContentControl selectedItem, bool dynamicInsert)
  2. {
  3.     var doc = AcApp.DocumentManager.MdiActiveDocument;
  4.     var db = doc.Database;
  5.  
  6.     // Блокируем документ
  7.     using (doc.LockDocument())
  8.     {
  9.         using (var tr = doc.TransactionManager.StartTransaction())
  10.         {
  11.            
  12.             // Копируем таблицу из файла ресурсов - для вопроса не важно
  13.            
  14.             // Масштабируем до перемещения для правильного отображения
  15.             var mat = Matrix3d.Scaling(Scale(CbScales.SelectedItem.ToString()), tbl.Position);
  16.             tbl.TransformBy(mat);
  17.  
  18.             if (dynamicInsert)
  19.             {
  20.                 // Перемещаем с джигой
  21.                 var jig = new TableDrag();
  22.                 var jigresult = jig.StartJig(tbl, pointAligin);
  23.                 if (jigresult.Status != PromptStatus.OK)
  24.                 {
  25.                     tbl.Erase();
  26.                     return;
  27.                 }
  28.                 tbl.Position = jig.TablePositionPoint();
  29.                 doc.TransactionManager.QueueForGraphicsFlush();
  30.             }
  31.  
  32.             // Потом настройка таблицы - для вопроса не важно
  33.  
  34.             tr.Commit();
  35.         }
  36.     }
  37. }
Ну и "джига":
Извините, вам запрещён просмотр содержимого спойлеров.

Изначально в коде использовался EntityJig. Потом я изменил на DrawJig - случаи возникновения ошибок стали реже

Единственная надежда которая осталась - что более опытные разработчики "на глаз" смогут выдвинуть правильное предположение  ;)

Важное замечание: Ошибка возникает при работе в AutoCad 2016. Попробовал - "больной" файл пересохранил в 2010 и проверил - ошибки нет. 2011-2015 не пробовал. В 2017 автокаде ошибки тоже нет!
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Привалов Дмитрий от 04-04-2016, 08:37:25
Эта проблема не дает мне покоя уже оооочень много времени!

Попробуй вызвать Dispose() на mat, jig, jigresult после их использования. Как вариант заключи в блок using (....). Скорее всего поможет.
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 08:42:19
Попробуй вызвать Dispose() на mat, jig, jigresult после их использования
Проблема в том, что ошибка происходит во время jig, а не после
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Привалов Дмитрий от 04-04-2016, 08:51:03
Проблема в том, что ошибка происходит во время jig, а не после
переменные однако ты тоже объявляешь во время jig, а не после ;-)
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Дмитрий Загорулькин от 04-04-2016, 10:19:37
// Копируем таблицу из файла ресурсов - для вопроса не важно
Думаю, что в этой части может быть проблема.
Как вариант - проблемы с кодом вообще нет, а есть проблема с AutoCAD 2016 на отдельно взятой машине :)
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 10:37:21
Как вариант - проблемы с кодом вообще нет, а есть проблема с AutoCAD 2016 на отдельно взятой машине
Проблема с 2016 автокадом, только не на отдельно взятой машине, а в отдельно взятых файлах

И как я уже написал - если исключить из кода jig (просто указание точки и перемещение таблицы в эту точку), то ошибки нет
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Привалов Дмитрий от 04-04-2016, 12:49:52
если исключить из кода jig (просто указание точки и перемещение таблицы в эту точку), то ошибки нет
Dispose() попробовал?
если исключить из кода jig (просто указание точки и перемещение таблицы в эту точку), то ошибки нет
Из кода не понятно как создан tbl? это резидент или не резидент в базе данных.  Может и не важно, но по коду не догадаться.
Очень смущают строчки tbl.Erase(); а после tbl.Position = jig.TablePositionPoint(); смахивает на обращение  к свойству удаленного объекта.
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Привалов Дмитрий от 04-04-2016, 12:50:13
если исключить из кода jig (просто указание точки и перемещение таблицы в эту точку), то ошибки нет
Из кода не понятно как создан tbl? это резидент или не резидент в базе данных.  Может и не важно, но по коду не догадаться.
Очень смущают строчки tbl.Erase(); а после tbl.Position = jig.TablePositionPoint(); смахивает на обращение  к свойству удаленного объекта.
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 12:58:09
Из кода не понятно как создан tbl? это резидент или не резидент в базе данных
Таблица копируется в текущую БД с помощью WblockCloneObjects. Т.е. до момента перемещения таблица уже присутствует в чертеже. По рукой кода нет, могу только через декомпилятор показать
Извините, вам запрещён просмотр содержимого спойлеров.

Ну а Erase() срабатывает только если пользователь отменил работу Jig. Т.е. такого как вы написали - Очень смущают строчки tbl.Erase(); а после tbl.Position = jig.TablePositionPoint(); - не происходит
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Ривилис от 04-04-2016, 13:04:51
Александр Пекшев aka Modis,
После  tbl.Erase(); я но не хватает tr.Commit(); если конечно tbl содержится в базе. В прочем в этом случае мне не понятно зачем DrawJig - его обычно используют для объектов не содержащихся в базе.
Еще смущает _currPoint.DistanceTo(_prevPoint) > 1e-6; - слишком часто будет перерисовываться таблица.
Да и вообще этот тот случай, когда лучше было бы рисовать прямоугольник вместо таблицы. Его значительно легче спозиционировать.
Еще вместо:
Код - C# [Выбрать]
  1.             draw.Geometry.Draw(_table);
  2.  
  3.             return true;
я бы использовал
Код - C# [Выбрать]
  1.             return draw.Geometry.Draw(_table);
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 13:09:17
Еще смущает _currPoint.DistanceTo(_prevPoint) > 1e-6; - слишком часто будет перерисовываться таблица
Думаю вот тут и основная проблема, т.к. иногда автокад вылетает с ошибкой "Недостаточно памяти".
Александр, посоветуйте другое значение предела сравнения
Да и вообще этот тот случай, когда лучше было бы рисовать прямоугольник вместо таблицы. Его значительно легче спозиционировать
Если не сработает изменение предела, то попробую использовать просто прямоугольник

Почему DrawJig вместо EntityJig? Так случилось в процессе экспериментов по поиску и устранению ошибки. Да так и осталось :)
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Ривилис от 04-04-2016, 13:16:10
Александр, посоветуйте другое значение предела сравнения
У меня обычно 1e-3, хотя и это может быть слишком мелким значением. Всё зависит от текущего масштаба единиц. Условно говоря если ты имеешь дело со строительным чертежом, в котором единицы - миллиметры, то 1e-1 будет вполне достаточно.
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 13:17:16
Александр Ривилис, спасибо. Вечером буду экспериментировать ))
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Ривилис от 04-04-2016, 13:23:42
Еще поэкспериментируй с установкой tbl.SuppressRegenerateTable(true);
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Привалов Дмитрий от 04-04-2016, 14:30:54
Вечером буду экспериментировать ))
У тебя сразу после 1ого запуска команды ошибки или после 2-3 ого?
Dispose все-таки проверь, т.к. либо ты вызовешь его либо за тебя это сделает сборщик мусора и позже, например во время 2-3 выполнения команды.
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 04-04-2016, 14:33:14
У тебя сразу после 1ого запуска команды ошибки или после 2-3 ого?
Сразу после первого и только в 2016 автокаде, и только в определенных файлах
Dispose тоже протестирую на всякий случай
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 05-04-2016, 21:31:40
Александр Ривилис, Вы прям волшебник зоркости! С ходу предложили несколько вариантов, включая тот, который помог!
Добавил перед jig tbl.SuppressRegenerateTable(true); и после соответственно tbl.SuppressRegenerateTable(false);  и все заработало!
Остальные замечания так-же учту и подправлю
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Ривилис от 05-04-2016, 21:36:44
Добавил перед jig tbl.SuppressRegenerateTable(true); и после соответственно tbl.SuppressRegenerateTable(false);  и все заработало!
Догадываешься почему?
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Пекшев aka Modis от 05-04-2016, 21:41:57
Добавил перед jig tbl.SuppressRegenerateTable(true); и после соответственно tbl.SuppressRegenerateTable(false);  и все заработало!
Догадываешься почему?
Я про этот метод первый раз услышал, если честно) Но из простого перевода метода все понятно - подавление регенерации таблицы. Т.е. при jig не происходит ее постоянной перерисовки (это в моем случае). Думаю, что полезно этот метод включать перед всеми действиями с таблицой и отключать в конце работы функции, перед tr.Commit()
Название: Re: Фатальная ошибка при работе DrawJig
Отправлено: Александр Ривилис от 05-04-2016, 22:19:59
Всё еще интереснее. Класс Table наследник класса BlockReference:
(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fimg-fotki.yandex.ru%2Fget%2F59115%2F7842324.5%2F0_11fa55_af5316a1_orig.png&hash=bc70473ab6ce62f01e6cff68997dab62)
Изменения в таблице приводят к генерации новых BlockTableRecord, на которые таблица ссылается также, как и обычный BlockReference.
По какой-то причине изменение точки вставки таблицы в твоём случае приводит к генерации новой BlockTableRecord, которая она добавляется в базу данных, и на которую таблица ссылается. Возможно это особенность конкретной таблицы (например, со вставленными динамическими блоками). И это происходит многократно, десятки или даже сотни раз в секунду. Плюс вполне вероятно происходит утечка памяти...