Хочу вызвать данную команду через acedCmdLookupЗачем? Есть куча других способов для этого. Кстати, команда _REMOVEALLPROXY - модальная, работающая только с текущим/активным чертежом, по этой причине не блокирует его и соответственно прямым вызовом может вызываться только из определенных контекстов.
Есть куча других способов для этого?Возможно :)
но есть другие команды которые я не могу использовать через RunCommand так как он не ждет окончанияЖдет. Ты путаешь RunCommand с SendCommand. RunCommand - это непубличный метод класса Editor, который нужно вызвать хитрым способом.
acedCmd не работает с CommandFlags.SessionМне не очень понятно зачем тебе запускать команду из контекста приложения. Но если даже это и нужно, то делается это просто: делаешь фиктивную команду с флагом Modal, которую запускаешь из контекста приложения через AcadDocument.SendCommand или Document.SendStringToExecute. А все остальные действия выполняешь именно в этой команде.
А перевести можно и исходники выложить. Буду ждать. Спасибо.
Несколько замечаний по коду. Строка 93 третьей части кода:Спасибо. Close там был но потом я его при рефакторинге случайно удалил, а вот то, что Dispose нужен не знал, учту.
Код - C#: [Выделить]
DBObject dbObj = ids[j].Open(OpenMode.ForWrite, false);
Ты открываешь это объект, но нигде не закрываешь его. Если dbObj.Erase(true) выполнилось успешно, то нужно вызвать dbObj.Close(). Если возникло исключение и мы пользуемся для удаления
Если explode возвращает 0 примитивов то выполнять proxy++ не стоит (по моему мнению), т.к. данный ACAD_PROXY_ENTITY исчезает из быстрого выбора, но в чертеже содержится и при следующем открытии будет снова доступен.Эту мысль я что-то не понял. В моём коде вне зависимости от того что возвращает explode сам примитив потом удаляется и поэтому proxy++ справедливо.
Цитата: T72 от 06-11-2014, 14:16:00Данная функция для разбиения прокси на примитивы - значит если не получилось разбить то не стоит удалять, для этого есть другая функция.
Если explode возвращает 0 примитивов то выполнять proxy++ не стоит (по моему мнению), т.к. данный ACAD_PROXY_ENTITY исчезает из быстрого выбора, но в чертеже содержится и при следующем открытии будет снова доступен.
Эту мысль я что-то не понял. В моём коде вне зависимости от того что возвращает explode сам примитив потом удаляется и поэтому proxy++ справедливо.
ну и спасибо тебе за то, что навёл меня на баг в моей версии. В версиях начиная с 2013 список масштабов в команде REMOVEALLPROXY не чистился. Причина банальная - перенос функции acedResetScaleList в accore.dll. Подправил свои исходники и выложил исправленные arx-файлы.Александр, а можно сделать "финт ушами"? То есть сделать по 2 arx-модуля: с чисткой масштабов и без оной? Честно говоря, я был безумно рад, что запроса по чистке масштабов не стало...
Данная функция для разбиения прокси на примитивы - значит если не получилось разбить то не стоит удалять, для этого есть другая функция.Ага. С этой логикой я согласен.
Александр, а можно сделать "финт ушами"?Запросто. Тем более что теперь на форуме выложены даже два варианта кода: и ObjectARX, и .NET API. Так что можешь для себя сделать любую сборку. :)
Эта конструкция в корне неправильна:
Код - C#: [Выделить]
proxyEntity.Explode(aExplProxy);
if (aExplProxy.Count > 0)
{
proxy++;
proxyEntity.Erase(true);
Line line = new Line();
proxyEntity.HandOverTo(line, false, false);
line.Close();
line.Dispose();
}
1. Ты сначала удаляешь proxyEntity, и не проверив удачно ли это получилось выполняешь повторное удаление при помощи HandOverTo
2. После HandOverTo ты делаешь line.Close() - это правильно, т.к. теперь line - это примитив в базе. А где же line.Erase() ?
3. Нужно делать не line.Dispose(), а proxyEntity.Dispose()
Мы тут уже на форуме это обсуждали, что если объект/примитив AutoCAD содержится в базе (т.е. его ObjectId отличен от 0), то метод Dispose() для него эквивалентен методу Close(), а если примитив не содержится в базе (т.е. его ObjectId равен 0), то метод Dispose эквивалентен освобождению памяти этого примитива.
Таким образом line.Close(); и line.Dispose(); - эквивалентны, зато нет освобождения памяти proxyEntity
Александр, а можно сделать "финт ушами"? То есть сделать по 2 arx-модуля: с чисткой масштабов и без оной? Честно говоря, я был безумно рад, что запроса по чистке масштабов не стало...Два варианта не нужны. Просто на уровне API нужно отделять мух от котлет: отдельные команды по работе с proxy и отдельные по работе со списком аннотативных масштабов. Затем различные комбинации этих методов заворачиваются в виде команд CAD системы. Т.е. отдельные команды для взрыва и удаления proxy и отдельная для очистки списка аннотативных масштабов. Я себе это оформил в виде методов со следующими сигнатурами:
вы полагаете, что может оказаться существенная разница между разностью (iLast - iFirst) и значением nObjects и тем самым решили добавить дополнительную проверку, дабы максимально сократить цикл?Да. Я сталкивался с такой ситуацией несколько раз. Если мне не изменяет память я тебе рассказывал, что в изначальном коде iFirst был равен 0, но оказалось, что бывают чертежи у которых первая "живая" метка имеет очень большой номер и программа может очень длительное время перебирать метки (минутами, если не часами). Аналогично и с iLast. Достаточно просто сохранить чертеж в DXF-формате, изменить значение системной переменной $HANDSEED на какое-то очень большое и потом снова пересохранить в dwg-формат. Аналогичная ситуация возможна при получении чертежа из программ, которые генерируют DXF-файлы, если они не корректно вычисляют $HANDSEED.
Код T72 мне не понравилсяЧто так? В основном T72 переводил мой код с C++ на C# (по мере возможности) без изменений. Мой код тоже не блещет изяществом. Первая версия его писалась > 15 лет назад и с годами просто адаптировалась к новым версиям без существенной переработки.
Что так? В основном T72 переводил мой код с C++ на C# (по мере возможности) без изменений.Именно поэтому, ведь C# это всё же не C++.
Если мне не изменяет память я тебе рассказывал...Я такого не помню.
Я такого не помню.Склероз у тебя. :-) Это было тогда, когда я поделился с тобой алгоритмом прохода по всем Handle в чертеже. Если помнишь, ты еще проверял какой из алгоритмов быстрее позволяет получить ObjectId по Handle. Были варианты: 1) Database.GetObjectId 2) P/Invoke для AcDbDatabase::getAcDbObjectId и 3) Database.TryGetObjectId - самый быстрый.
можно было бы заменить более компактным вариантом:Он несколько компактнее по форме записи, но требует дополнительной проверки на неравенство нулю proxy в каждом операторе if. Так что тут дело вкуса. Тем более я не могу предугадать как этот код оптимизирует компилятор C++.
требует дополнительной проверки на неравенство нулю proxy в каждом операторе if.Но ведь вас не смутила двойная проверка на равенство AcDbProxyEntity::kFullGraphics. :)
Это было тогда, когда я поделился с тобой алгоритмом прохода по всем Handle в чертеже. Если помнишь, ты еще проверял какой из алгоритмов быстрее позволяет получить ObjectId по Handle.Я помню, что вы поделились, равно как и помню эти сравнения (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/compare). Однако про дополнительную проверку за счёт уменьшения значения approxNumObjects() информации всё же не помню (возможно прослушал). Мой код, который вы упомянули, не использовал эту проверку (здесь (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/dbsearcher), в коде строка 87).
Однако про дополнительную проверку за счёт уменьшения значения approxNumObjects() информации всё же не помню (возможно прослушал).Ты невнимательно прочитал. Я напоминал тебе про старый разговор о стартовом номере, т.е. что Handle нужно начинать не с 0, а с db.BlockTableId.Handle. Про конечный номер мы не тогда не говорили, но с ним аналогично - дополнительная проверка не помешает.
Александр, Андрей - я уверен что считать строки и байты - это немножко не ваш уровень.Ты в данном случае про какие байты?
На которые код стал "лучше".А! Я думаю что ты прав и мы не будем обсуждать стили программирования, а будем обсуждать существо программы. Например, я уже много лет собираюсь, но так и не реализовал такую интересную штуку, которая касается ExplodeAllProxy. Метод Explode далеко не всегда возвращает то, что соотвествует тому, что видно на экране. Достаточно часто изображение сдвинуто, повернуто и т.д. Чтобы получить реальное изображение proxy-примитива нужно:
На мой взгляд, стоит забыть уже про высказывания о качестве кода, стили разные, да и обращать внимание на попытку сконцентрировать внимание на if-е, человеком который уже несколько раз просрочил завтра тоже не стоит (Андрей, если ты ратуешь за качество и производительность то должен знать, что switch намного быстрее if-а при перечислениях т.к позволит компилятору сделать хэш-меп и сразу выбрать значение). Нужно развивать идею с AcGiWorldDraw или закрывать тему.Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.
Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.Я подозреваю, что это реакция на это:
Код T72 мне не понравился, поэтому написал свою альтернативу.Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.
Цитата: Алексей Кулик от 16-11-2014, 16:29:51Да ну бросьте, если бы мне хотелось с кем то спорить и что-то доказывать то я отреагировал бы сразу после того поста. А так просто уже от темы в сторону стали уходить, поэтому я и написал, что стоит дальше развивать идею с "правильным" расчленением объектов или закрывать ее.
Чего? Я несколько раз перечитал текст, но так ничего внятного и не понял.
Я подозреваю, что это реакция на это:
Цитата: Андрей Бушман от 12-11-2014, 20:01:39
Код T72 мне не понравился, поэтому написал свою альтернативу.
Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.
Надеюсь, что до виртуального рукоприкладства дело не дойдет. Иначе придётся принимать меры, а делать это мне очень не хочется.Я игнорирую, так что не дойдёт. :)
Command: explodeallproxy
Удалено Proxy: 230 Новых объектов: 3834
Command: removeallproxy
Первая метка объекта: <1>, последняя метка объекта: <34A9>
Всего найдено proxy-объектов: 4609. Из них proxy-примитивов: 0.
Всего удалено proxy-объектов: 4609. Из них proxy-примитивов: 0.
Для проверки ошибок выполните команду _AUDIT
Command: test
DBObjects count before: 5565.
including ProxyEntity items count: 230;
including ProxyObject items count: 4609;
All ProxyEntity items exploded.
New DBObjects count: 3834.
All ProxyObject items removed.
Unused annotation scales count: 24.
Unused annotation scales removed.
DBObjects count after: 4869.
Run the _AUDIT command with the _Y option, please.
замечания приветствуютсяЗаметил по отчету, что DBObjects count меняется не "арифметически":
Это нормально?Нужно будет поразбираться, почему не бьётся сумма.
Command: test
DBObjects count before: 5547.
including ProxyEntity items count: 230;
including ProxyObject items count: 4591;
All ProxyEntity items exploded.
New DBObjects count: 3834.
All ProxyObject items removed.
Count of 'HandOverTo' operations for the ProxyEntity items: 0.
Count of 'HandOverTo' operations for the ProxyObject items: 131.
Unused annotation scales count: 24.
Unused annotation scales removed.
DBObjects count after: 4860.
Ellapsed time [Hours:Minutes:Seconds:Milliseconds]: 0:0:0:627
Run the _AUDIT command with the _Y option, please.
А почему при удалении прокси-объекта сразу не делать его подмену "пустышкой", без попыток удаления?Она не совсем пустышка и если делать много подмен (десятки/сотни тысяч), то база чертежа будет расти в памяти до того момента, пока чертеж не будет сохранён и открыт повторно. Я бы это делать не рекомендовал.
Она не совсем пустышка и если делать много подмен (десятки/сотни тысяч), то база чертежа будет расти в памяти до того момента, пока чертеж не будет сохранён и открыт повторно. Я бы это делать не рекомендовал.Я так понял, что он спрашивает о том, почему бы не ограничиться только HandOverTo. Насчёт "будет расти в памяти" я не понял. Смотрим код:
аз пошла такая пьянка, то зачем в Using Close?Чтобы применить это:
Чтобы применить это:А bender прав. После HandOverTo у line появляется ненулевой ObjectId и соотвественно line.Dispose() приводит к line.Close(). Так что вызов line.Close() лишний.
То что удаляется через Erase - удаляется не сразу, а только при сохранении чертежа.Тогда тем более:
Как в первом, так и во втором случаях - мы в итоге вызываем Erase.Но в первом случае ты вызываешь Erase для примитива, который уже находится в базе. Соотвественно объем памяти не изменяется. Во втором случае ты вызываешь Erase для примитива, который только что добавлен в базу. Вот за счет этого и возможно увеличение памяти.
Именно по этой причине в фильтр я и добавил проверку ObjectId.IsEffectivelyErased.Но в этом случае у тебя скорее всего не будет сходится статистика.
Но в этом случае у тебя скорее всего не будет сходится статистика.Да она и до этого не сходилась.
Все дружно шлём апельсины (не путать с помидорами) в адрес Дмитрия Загорулькина, напомнившего о существовании перегруженной версии метода1) Про этот метод я помнил, но он появился только в AutoCAD 2009, так что для тебя он актуален, но в случае необходимости писать универсальный код - не подходит (это касается и чистого ObjectARX)
Код - C#: [Выделить]
Transaction.GetObject Method (ObjectId, Autodesk.AutoCAD.DatabaseServices.OpenMode, [MarshalAs(UnmanagedType.U1)] bool, [MarshalAs(UnmanagedType.U1)] bool)
Последний параметр позволяет открывать и править объекты на заблокированных слоях. Т.о. отваливается необходимость и в методе GetLockedLayerIds, а так же в файле LayoutLockingSwitcher.cs.
но стандартные масштабы.у иностранцев свой список стандартных масштабов, а в России свой. Так что удаление их стандартных записей нам [проектировщикам компании, в которой я работаю] только на руку - не будут попусту глаза мозолить.
но в случае необходимости писать универсальный код - не подходит"Универсальность" - понятие относительное... Например для меня это слово означает переносимость на уровне кода для AutoCAD 2009 и выше (более старые версии мне не интересны), а так же между различными CAD платформами (AutoCAD, nanoCAD, BricsCAD и т.п.).
Например для меня это слово означает переносимость на уровне кода для AutoCAD 2009 и выше (более старые версии мне не интересны)Считай, что это было не для тебя, а для тех, кто еще пишет под версии AutoCAD до 2009.
Допустим использовали только масштаб 1:2, ты все остальные масштабы удалил. Теперь пользователю самому придется создать масштаб 1:1.Подразумевается, что полная очистка, в т.ч. и масштабов, происходит в самом конце работы, когда документ оформлен и его нужно очистить от лишнего. Кроме того, у меня есть отдельная команда, которая создаёт список аннотативных масштабов по госту, считывая все возможные варианты из внешнего XML файла, так что восстановить гостовские масштабы (при необходимости) не проблема. Да и не только их, т.к. XML можно подредактировать как угодно.
Подразумевается, что полная очистка, в т.ч. и масштабов, происходит в самом конце работы, когда документ оформлен и его нужно очистить от лишнего.Я, например, чаще чищу чертежи, полученные от кого-то, до работы с ними (иначе их нередко ни чем не "повернуть").
Я, например, чаще чищу чертежи до работы с ними (иначе их нередко ни чем не "повернуть").
Кроме того, у меня есть отдельная команда, которая создаёт список аннотативных масштабов по госту, считывая все возможные варианты из внешнего XML файла, так что восстановить гостовские масштабы (при необходимости) не проблема. Да и не только их, т.к. XML можно подредактировать как угодно.
T72, я хотел бы уточнить (так как не тестировал твой код). Твой код после всех исправлений на форуме сейчас работает нормально, т.е. можно считать, что это полностью работоспособный вариант или нужно его править?Добрый день. Извиняюсь за столь долгий ответ, тестировал функции. Пока все работает хорошо, добавил еще один try/catch т.к. в одном из цивиловских фалов возникла ситуация при которой точка COGO не хотела удаляться, код в сообщении подправил.
в одном из цивиловских фалов возникла ситуация при которой точка COGO не хотела удалятьсяМожешь выложить этот DWG файл для тестирования?
Вспомнил я еще про такой метод: Database.ReclaimMemoryFromErasedObjects, который позволяет освободить оперативную память, занятую удаленными (методом Erase) объектами.Спасибо, полезная информация. Добавлю в код.
Autodesk.AutoCAD.Runtime.Exception was unhandled by user code
Message=ePermanentlyErased
Source=acdbmgd
StackTrace:
at Autodesk.AutoCAD.DatabaseServices.Database.ReclaimMemoryFromErasedObjects(ObjectIdCollection ids)
at Bushman.CAD.Commands.Command_ClearUnusedAnnotativeScales() in c:\Users\developer\Documents\Visual Studio 2013\Projects\DwgResave_solution\Acad2009_Proxy\Commands.cs:line 82
at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object commandObject, Boolean bLispFunction)
at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorkerWithExceptionFilter(MethodInfo mi, Object commandObject, Boolean bLispFunction)
at Autodesk.AutoCAD.Runtime.PerDocumentCommandClass.Invoke(MethodInfo mi, Boolean bLispFunction)
at Autodesk.AutoCAD.Runtime.CommandClass.CommandThunk.Invoke()
InnerException:
Добрый день. Извиняюсь за столь долгий ответ, тестировал функции. Пока все работает хорошо, добавил еще один try/catch т.к. в одном из цивиловских фалов возникла ситуация при которой точка COGO не хотела удаляться, код в сообщении подправил.Я не зря задал этот вопрос. Судя по коду у тебя не должны удаляться "неудаляемые" прокси-объекты/прокси-примитивы. В твоем коде если не срабатывает метод Erase(), то вызывается:
Специального признака того, что объект освобожден нет.Жаль. Этот функционал не помешал бы.
Несмотря на то, что у тебя при вызове Database.ReclaimMemoryFromErasedObjects возникает исключение, тем не менее (согласно документации) все объекты обрабатываются, а исключение генерируется если хотя бы один из объектов уже освобожден (см. описание метода AcDbDatabase::reclaimMemoryFromErasedObjects).Т.е. вы хотите сказать, что исключение вываливается не на первом же уже удалённом объекте, но "в уме" запоминается, что такой объект присутствует и пробежав по всем элементам, обработав нужные, исключение вываливается после полной обработки? В этом случае просто нет смысла в исключении, поскольку AutoCAD мог просто в итерации пропускать "инвалидов" и обрабатывать только "валидов". Если так, то будет достаточно этот код засунуть в try\catch с пустым catch.
в одном из цивиловских фалов возникла ситуация при которой точка COGO не хотела удалятьсяОгрызок от файла http://file.sngp.ru/fileshare/d0f03cf0-5f57-42bf-a464-310102aba44d в нем эти точки, при эрейзе в эксплоде ругается eNotAllowedForThisProxy, но при повторном вызове их уже нет.
Можешь выложить этот DWG файл для тестирования?
Огрызок от файлаЯ не нашёл в этом файле ни одного proxy.
Цитата: T72 от 21-11-2014, 12:09:068 прокси там, нужно открыть в обычном автокаде и отключить энейблеры, если таковые имеются.
Огрызок от файла
Я не нашёл в этом файле ни одного proxy.
Но нигде нет tmpObj.Erase(); :(Да вы правы, имеет место досадная невнимательность, добавил, но и без нее работало. Ошибка с COGO точкой возникает при EXPLODEALLPROXY, а не REMOVEALLPROXY.
Так что или код у тебя работает не всегда, или на форуме не окончательный код. Проверь пожалуйста.
8 прокси там, нужно открыть в обычном автокаде и отключить энейблеры, если таковые имеются.я добавил UPD в предыдущем сообщении.
8 прокси таму меня показывает следующие цифры:
Command: proxyГолый AutoCAD 2009.
21 ProxyEntity and 2583 ProxyObject items found.
Unhandled Access Violation Reading 0x0008 Exception at 8d0076h
System.AccessViolationException occurredПричину ошибки нашёл, исправил. Чуть позже обновлю исходники.
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=acdbmgd
StackTrace:
at AcDbEntity.blockId(AcDbEntity* , AcDbObjectId* )
at Autodesk.AutoCAD.DatabaseServices.Entity.get_BlockId()
at Bushman.CAD.ExtensionMethods.ExplodeProxyEntity(ObjectId proxyEntityId, Boolean& handOverTo_called) in c:\Users\developer\Documents\Visual Studio 2013\Projects\DwgResave_solution\DwgRecovery_x64\ExtensionMethods.cs:line 202
InnerException:
В виду этого я перенёс репозиторий cadproxy на BitBucket, после чего удалил свой GitHub-аккаунт.Андрей, в файле readme ссылка FEEDBACK осталась на github
Андрей, в файле readme ссылка FEEDBACK осталась на githubИсправил. Кстати, удалить профиль на GitHub, в свете перехода на BitBucket, было опрометчивым решением, т.к. он может пригодиться при работе с чужими проектами, размещёнными на нём. В виду этого профиль был на всякий случай восстановлен.
Или тут проще не заморачиваться и плюнуть? ;)Вполне возможно, что это наведёт Андрея на ошибку, т.к. если прокси в файле нет, то и его программа ничего находить не должна.
Если надо - могу завтра на работе еще раз смоделировать ситуацию и выдать любую нужную информацию.Буду признателен. Выкладывание обозначенных DWG файлов так же приветствуется, дабы можно было под отладчиком посмотреть что к чему.
Или тут проще не заморачиваться и плюнуть? ;)Я всегда за исправление багов.
Вполне возможно, что это наведёт Андрея на ошибку, т.к. если прокси в файле нет, то и его программа ничего находить не должна.Или обнаружится ещё один баг в моём коде :)
Ок, тогда завтра займусь. Вполне может оказаться, что я по незнанию что-то намудрил с кодом при пересборке.Или у тебя файл шаблона по-умолчанию содержит прокси объекты, которые ExplodeAllProxy почему-то пропускает.
подчеркиваю - я не понимаю как работает код; единственное что я сделал - это его скомпилировал под мои привычные условия использованияА мне почему-то запомнилось, что ты там что-то химичил (http://autolisp.ru/2015/02/02/managed-alternative-explodeallproxy/) от себя :) :
Ниже показан исправленный мною код. Я поменял код так, чтобы хоть что-то в нем понять (Андрей, прости!)Я не сравнивал с оригиналом, поэтому не знаю характер и объём произведённых тобой изменений (форка на битбукете не было).
Или у тебя файл шаблона по-умолчанию содержит прокси объекты, которые ExplodeAllProxy почему-то пропускает.А что, разве такое возможно? В каких случаях?
C#-переделку выкладывать?Неа. Я в оригинале для начала найти должен. Если что - тебе не составит труда скопипастить свои изменения в обновлённую версию, если мне удастся найти причины кривизны моего кода (надеюсь, что удастся). К сожалению, завтра меня не будет на работе... :( Постараюсь завтра и на выходных из дома посмотреть.
Теоретически возможно, если они прошли через "шаловливые ручки" вертикальных приложений.Т.е. шаблоны ты создавал на вертикалке? Мне всё равно не понятно, в каких случаях код А.Н. Ривилиса для таких шаблонов может не находить прокси будучи запущенным в голом акаде...
Возможно что? Создать файл шаблона, содержащий прокси-примитивы? Или ExplodeAllProxy может пропустить прокси объект?Или у тебя файл шаблона по-умолчанию содержит прокси объекты, которые ExplodeAllProxy почему-то пропускает.А что, разве такое возможно? В каких случаях?
Возможно что? Создать файл шаблона, содержащий прокси-примитивы? Или ExplodeAllProxy может пропустить прокси объект?Конечно же второй вариант...
Конечно же второй вариант...Может. В отличие от RemoveAllProxy, который сканирует всю базу, ExplodeAllProxy работает только с теми контейнерами, которые могут содержать примитивы, а именно с (AcDb)BlockTableRecord'ами содержащимися в (AcDb)BlockTable. Т.е. если гипотетически предположить, что владельцем прокси-примитива будет не блок (том числе *ModelSpace, *PaperSpace, *PaperSpaceX), то ExplodeAllProxy его пропустит и обрабатывать не будет. Теоретически владельцами (AcDb)Entity могут быть только (AcDb)BlockTableRecord, но чем черт не шутит...
Но, может, у Александра такой объект действительно не распознается как прокси при таких условиях, а у тебя - распознается? Это все в качестве предположения...Насколько я помню, то фильтрацию проксей я делал по аналогии с кодом А.Н. так что ожидались и одинаковые результаты. Нужно будет глянуть и сравнить...
На одном чертеже словил, что создаются примитивы от разбивки, но сами прокси не удаляются.Как ты открывал свой proxyEntity (через транзакцию или без)?
Внимание! Если в коде не используется OpenCloseTransaction (ниже в коде я покажу оба варианта), то после того, как замещяемый объект (Circle в примере выше) открыт с опцией OpenMode.ForWrite - для него позднее должен быть обязательно вызван метод Dispose(), а для замещающего - метод Close() для того, чтобы зафиксировать изменение и закрыть запись в файле "UNDO.ac$". Обратите внимание на то, что удалять старый объект (Circle в примере выше), вызывая экземплярный метод Erase(), в данном случае не нужно, так как эта операция удаления выполняется в коде метода DBObject.HandOverTo(). Однако очистка памяти от замещаемого объекта (Circle в примере выше) путём вызова его метода Dispose() нужна, т. к. в коде метода HandOverTo() эта очистка не выполняется.
Теоретически владельцами (AcDb)Entity могут быть только (AcDb)BlockTableRecord, но чем черт не шутит...Подтверждаю. На практике попадалась пара чертежей, в которых примитивы лежали не там, где надо, т.е. не в BlockTable. Предполагаю, что это результат вылетов во время сохранения, или неудачного копирования и последующего сохранения.
Как ты открывал свой proxyEntity (через транзакцию или без)?Без. насколько помню HandOverTo не работает с объектами транзакций вызывая исключение.
насколько помню HandOverTo не работает с объектами транзакций вызывая исключение.угу
Метод DBObject.HandOverTo()не разрешён к использованию на объектах, которые являются резидентными объектами транзакции.
Предполагаю, что это результат вылетов во время сохранения, или неудачного копирования и последующего сохранения.Только не это. Теоретически владельцем (AcDb)Entity может оказаться (AcDb)DBDictionary, но он для этого не предназначен.
Только не это. Теоретически владельцем (AcDb)Entity может оказаться (AcDb)DBDictionary, но он для этого не предназначен.В теории да, но на практике попадаются объекты, в том числе примитивы с OwnerId которого не существует в БД. Т.е. вне иерархии, либо объекты/примитивы у которых ownerId==ObjectId.Null;
Audit удаляет такие объекты.Скажем так. Я считаю, что перед расчленением/удалением прокси следует выполнить как минимум _AUDIT, а еще лучше _RECOVER. В этом случае все не имеющие владельцев объекты будут удалены. А после этого с чертежом уже можно работать.
Если надо - могу завтра на работе еще раз смоделировать ситуацию и выдать любую нужную информацию.Напоминаю.
Подозреваю, что у тебя "шалит" Database.ReclaimMemoryFromErasedObjects. В моём коде он не используется."Будем посмотреть".
Сегодня прогнал на 2009х64. Похоже, я где-то что-то намудрил: команды выдают 0 объектов, а лисп-функции сообщают, что в файле 2 прокси объекта (если я все верно понимаю).Ясно.
Подозреваю, что у тебя "шалит" Database.ReclaimMemoryFromErasedObjects. В моём коде он не используется.Да, если закомментировать все её вызовы в коде, то проблемный файл обрабатывается нормально. Хотите сказать, что это не баг API, но либо я вызывал функцию не к месту, либо некорректный набор идентификаторов передаю в параметре?
Хотите сказать, что это не баг API, но я вызывал функцию не к месту?Интуитивно я предполагаю, что после вызова этого метода с чертежом лучше ничего больше не делать, а сразу его сохранить и закрыть.
Но память освобождается, а ссылки на неё сохраняются пока база не закрыта. Это и приводит к непредсказуемым результатам.Если это так, то это конкретный баг...
Интересно, а в какой версии ты его проверял? Если мне не изменяет память, то этот метод появился в AutoCAD 2009.В нём и обнаружилась проблема. Соответственно в нём и тестировал.
This member function deletes the objects underneath the input object ids and performs some related cleanup.Заменил везде это
The object ids in the input array must already be erased, and they should reside in the invoked database. Objects owned by the objects listed in the input array will be erased unless they already are, and their memory also reclaimed.
All deleted objects and memory will be restored upon undo, and re-deleted upon redo, by use of their DWG filing members.
Total errors found 358 fixed 358
В нём и обнаружилась проблема. Соответственно в нём и тестировал.А в более свежих?
Если это так, то это конкретный баг...Вопрос только чей.
Objects owned by the objects listed in the input array will be erased unless they already are, and their memory also reclaimed.Вот это бы я выделил красным. При этом ссылки от других объектов на эти объекты становятся нарушенными (впрочем и без ReclaimMemoryFromErasedObjects тоже). Именно поэтому, когда я создавал REMOVEALLPROXY два десятка лет назад я понимал, что как минимум требуется _AUDIT таких чертежей. А возможно они будут невосстановимо убиты.
Вот это бы я выделил красным.Ну так это логично, что если зависимые от него объекты удалены, то и они будут подчищены.
Вопрос только чей.Намекаете на то, что мой? Я помню, что вы выше "интуитивно предполагали", однако в документации я не вижу информации о том, в каких контекстах этот метод следует вызывать, а в каких нельзя. Я вижу описание метода. Контекст, в котором я использую ReclaimMemoryFromErasedObjects выглядит вполне уместно, особенно если учитывать, что:
All deleted objects and memory will be restored upon undo, and re-deleted upon redo, by use of their DWG filing members.т.е. если я верно понял этот текст - операция, выполненная при помощи ReclaimMemoryFromErasedObjects может быть спокойно отменена или возобновлена командами undo и redo.
Именно поэтому, когда я создавал REMOVEALLPROXY два десятка лет назад я понимал, что как минимум требуется _AUDIT таких чертежей. А возможно они будут невосстановимо убиты.Это всё здорово, только какое отношение это имеет к текущему поведению ReclaimMemoryFromErasedObjects? Я вызвал метод в соответствии с тем, как его использование документировано в SDK, передавая ему идентификаторы объектов, удовлетворяющих условию использования этого метода. На выходе получил поломанный документ. Поясните своё "Вопрос только чей." в данном контексте.
Я вызвал метод в соответствии с тем, как его использование документировано в SDK, передавая ему идентификаторы объектов, удовлетворяющих условию использования этого метода. На выходе получил поломанный документ. Поясните своё "Вопрос только чей." в данном контексте.1. Audit ты запускал в том же сеансе работы с dwg-файлом или сохранил, открыл его и выполнил Audit?
Some specialized object classes may require cleanup beyond the scope of this function. Such requirements cannot be anticipated in this function, so the developer who utilizes this function is advised to beware, and to thoroughly test the stability of the set of custom classes they anticipate to input to this function. They may have to wrap calls to this function in a function that performs additional cleanup for specific classes.В данном случае тебе бы пришлось найти в базе все ссылки в других объектах на эти объекты (и все объекты, которыми они владеют и так далее по иерархии) и удалить эти ссылки или заменить их на что-то такое, что не приводит к ошибкам в структуре dwg-файла. Это очень и очень сложно. Так что остается уповать на корректность работы _AUDIT.
Использование ReclaimMemoryFromErasedObjects в AutoCAD 2016 не приводит к изчезновению примитивов и возникновению обозначенного выше окна с ошибкой (как это было в AutoCAD 2009). Однако последующий аудит находит кучу ошибок:Если не использовать ReclaimMemoryFromErasedObjects в 2016, аудит выдает 0 ошибок?
В данном случае тебе бы пришлось найти в базе все ссылки в других объектах на эти объекты (и все объекты, которыми они владеют и так далее по иерархии) и удалить эти ссылки или заменить их на что-то такое, что не приводит к ошибкам в структуре dwg-файла. Это очень и очень сложно. Так что остается уповать на корректность работы _AUDIT.Т.е. в сухом остатке - лучше не использовать вызовы ReclaimMemoryFromErasedObjects в коде расширений.
Если не использовать ReclaimMemoryFromErasedObjects в 2016, аудит выдает 0 ошибок?Я уже писал выше, что в этом случае аудит выдаёт 0 ошибок. В т.ч. и в 2016-м:
Command: NETLOAD
acad.proxy.R19.0.dll
© Andrey Bushman, 2016
Commands:
proxy - get count of ProxyEntity and ProxyObject in the current Database.
xProxy - explode all proxy in the current Database.
rmProxy - remove all ProxyEntities and ProxyObjects in the current Database.
rmScales - remove all unused annotation scales in the current Database.
Command: AUDIT
Fix any errors detected? [Yes/No] <N>:
Auditing Header
Auditing Tables
Auditing Entities Pass 1
Pass 1 22300 objects audited
Auditing Entities Pass 2
Pass 2 22300 objects audited
Auditing Blocks
466 Blocks audited
Auditing AcDsRecords
Total errors found 0 fixed 0
Erased 0 objects
Command: XPROXY
327 ProxyEntity items found.
327 ProxyEntity items exloded.
2700 new DBObjects created.
Count of 'HandOverTo' operations: 0.
Run the _AUDIT command with the _Y option, please.
Command: AUDIT
Fix any errors detected? [Yes/No] <N>:
Auditing Header
Auditing Tables
Auditing Entities Pass 1
Pass 1 24700 objects audited
Auditing Entities Pass 2
Pass 2 24700 objects audited
Auditing Blocks
466 Blocks audited
Auditing AcDsRecords
Total errors found 0 fixed 0
Erased 0 objects
Command: RMPROXY
134 ProxyObject items found and removed.
Count of 'HandOverTo' operations: 0.
0 ProxyEntity items found and removed.
Count of 'HandOverTo' operations: 0.
Run the _AUDIT command with the _Y option, please.
Command: AUDIT
Fix any errors detected? [Yes/No] <N>:
Auditing Header
Auditing Tables
Auditing Entities Pass 1
Pass 1 24600 objects audited
Auditing Entities Pass 2
Pass 2 24600 objects audited
Auditing Blocks
466 Blocks audited
Auditing AcDsRecords
Total errors found 0 fixed 0
Erased 0 objects
Т.е. в сухом остатке - лучше не использовать вызовы ReclaimMemoryFromErasedObjects в коде расширений.Во всяком случае не в этом расширении. Если бы ты освобождал память из объектов, которые сам и создал и знаешь все их взаимосвязи, то этим методом можно было бы пользоваться.
Во всяком случае не в этом расширении. Если бы ты освобождал память из объектов, которые сам и создал и знаешь все их взаимосвязи, то этим методом можно было бы пользоваться.Ясно, спасибо.
На битбукете обновил версию исходников. Обозначенная выше ошибка исправлена, проект переделан так, чтобы при компиляции на выходе получался Bundle-пакет. Помимо аглицкого описания расширения присутствует и на русском. Откомпилированная версия так же обновлена (https://bitbucket.org/Andrey-Bushman/cadproxy/downloads ).
А именно использование Polyline3d вместо Polyline, как в оригинале у Александра, для отрисовки габаритов прокси,( если конечно кому-то нужен именно такой режим отображения)Стоп... В строке 110 кода функции ExplodeProxyInBTR (http://adn-cis.org/forum/index.php?topic=1060.msg4984#msg4984) я вижу использование AcDb3dPolyline. Мой C#-вариант идентичен. Поторопился я тебе плюсик ставить... :)
Мой C#-вариант идентичен.хм. а я смотрел не исходник, а прогнал ExplodeProxy2007.arx в 2008 автокаде. Более новые версии не смотрел.
Еще обрати внимание на ползунок, свойств для вершин и SequenceEnd примерно в 2 раза больше. и все храниться в чертеже.
В любом случае polyline на 4 вершины примерно в 6 раз меньше памяти займет чем Polyline3d.Однако Polyline использует 2D-точки в то время как прокси может быть смещённым и повёрнутым относительно всех трёх осей.
А именно использование Polyline3d вместо Polyline, как в оригинале у Александра, для отрисовки габаритов прокси,( если конечно кому-то нужен именно такой режим отображения)У меня AcDb3dPolyline. И сделано это умышленно, так как габариты могут в пространстве располагаться как угодно. AcDbPolyline пришлось бы крутить в пространстве. Да и вообще это как раз тот случай, когда полезной информации минимум, т.к. это информация о габаритном контейнере, а не о виде прокси-примитива. Заниматься дополнительной оптимизаций я счел лишним, но это не мешает тебе поступить иначе.
И сделано это умышленно, так как габариты могут в пространстве располагаться как угодно.То, о чём я и писал в предыдущем сообщении.
Polyline использует 2D-точки в то время как прокси может быть смещённым и повёрнутым относительно всех трёх осей.
У любой Entity есть свойство:
Matrix3d Ecs
в том числе у Polyline и даже SequenceEnd
смещай, поворачивай и масштабируй)
Ну по-хорошему нужно было бы строить ящик (AcDb3dSolid), чтобы он соответствовал габаритному контейнеру. Но кому это нужно?Оба варианта содержат разумное зерно, однако пока меня вполне устраивает и текущий вариант. Исходники в открытом доступе, так что любой желающий может их скопировать и подправить как ему нравится.
Ну по-хорошему нужно было бы строить ящик (AcDb3dSolid), чтобы он соответствовал габаритному контейнеру. Но кому это нужно?скорее всего не нужно, на крайний случай можно и Polyline выдавить с помощью свойства Thickness
насколько я понял GeometricExtents выдаст габарит без учета Ecs т.е. это 2 габаритные точки мин и макс, без всякого поворота. Или я не прав?
И сделано это умышленно, так как габариты могут в пространстве располагаться как угодно. AcDbPolyline пришлось бы крутить в пространстве
Грани габаритного контейнера всегда параллельны осям МСК (кроме случая когда примитив внутри блока, вставленного с поворотом).
т.е. крутить и учитывать в данном случае ничего не нужно. я правильно понял?Если 3D то вообще ничего не нужно. А если 2D, то нужно разбираться с Z.