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

ADN Club => AutoCAD .NET API => Тема начата: simson43 от 23-11-2018, 16:21:21

Название: Удаление всех внешних ссылок
Отправлено: simson43 от 23-11-2018, 16:21:21
Здравствуйте.
Нашел способ удаления всех внешних ссылок лишь перебором всего в модели, нахождения внешних ссылок и удаления каждой методом DetachXRef
есть ли проще?
Спасибо
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 23-11-2018, 16:48:46
есть ли проще?
А как ты себе представляешь это "проще"?
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 23-11-2018, 16:50:57
Какой-нибудь метод Database.RemoveAllXrefs(), наверное :)
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 23-11-2018, 17:08:09
Какой-нибудь метод Database.RemoveAllXrefs(), наверное :)
Работает, спасибо!)
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 26-11-2018, 12:33:42
я к тому, что делать итерацию внутри XrefGraph, наверное, быстрее чем внутри модели...
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 26-11-2018, 14:37:13
Не факт, надо проверять. Никто не гарантирует, что "внутри", при формировании XrefGraph, не используется тот же самый проход по всем объектам чертежа.
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 26-11-2018, 15:20:53
ну да если сравнивать цифры во время отладки то они одинаковые...
в таком варианте хотя бы код поприятнее.
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 26-11-2018, 15:22:32
Никто не гарантирует, что "внутри", при формировании XrefGraph, не используется тот же самый проход по всем объектам чертежа.
Нет. Зачем? И вообще проще просканировать BlockTable на предмет нахождения в ней BlockTableRecord, соответствующим внешним ссылкам и для них выполнить DetachXref.
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 26-11-2018, 16:30:11
а как из btr вытащить слой? только BlockReference получать?
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 26-11-2018, 16:34:04
И вообще проще просканировать BlockTable на предмет нахождения в ней BlockTableRecord, соответствующим внешним ссылкам и для них выполнить DetachXref.
Насколько я понимаю, нужно будет ещё дополнительно проверить, что эта внешняя ссылка не является вложенной в другую.
Кстати, а возможна же ситуация, когда внешняя ссылка вложена в блок чертежа? Тогда, получается, простая итерация по объектам модели или листов недостаточна. Надо ещё внутрь всех блоков входить... Маловероятно, конечно, что кто-то будет внешнюю ссылку в блок пихать. Но чего только не встретишь в реальности :)
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 26-11-2018, 16:34:22
а как из btr вытащить слой?
А кто-то в теме спрашивал про слой? Как нибудь определись с тем, что тебе нужно.
Если тебе нужно удалить только те внешние ссылки, которые вставлены на определённый слой (или слои), то конечно нужно анализировать вставки (BlockReference), а не Xref (BlockTableRecord). Тем не менее найти все BlockReference, которые относятся к данной BlockTableRecord без сканирования всей базы можно при помощи метода BlockTableRecord.GetBlockReferenceIds
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 26-11-2018, 16:35:48
Тогда, получается, простая итерация по объектам модели или листов недостаточна.
Конечно.
Насколько я понимаю, нужно будет ещё дополнительно проверить, что эта внешняя ссылка не является вложенной в другую.
Думаю, что да.
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 26-11-2018, 16:38:29
А может это и неважно. Возможно, что ничего страшного не случится, если "детачить" вложенную ссылку. Хотя, я бы на такое не надеялся :)
Надо проверять, тестировать...
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 14:56:12
А кто-то в теме спрашивал про слой? Как нибудь определись с тем, что тебе нужно.
мне нужно удалить то все! но если они лежат в заблокированном слое, то его нужно разблокировать сначала. а для этого узнать что за слой! так ведь?

а вот если проходить по BlockTable, то мне нужно открывать по ObjectId каждый btr и проверять что это внешняя ссылка?
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 28-11-2018, 14:59:39
но если они лежат в заблокированном слое, то его нужно разблокировать сначала. а для этого узнать что за слой! так ведь?
Не нужно, если открывать объект с соответствующей опцией forceOpenOnLockedLayer: http://help.autodesk.com/view/OARX/2018/ENU/?guid=OREFNET-Autodesk_AutoCAD_DatabaseServices_Transaction_GetObject_ObjectId_Autodesk_AutoCAD_DatabaseServices_OpenMode__MarshalAsUnmanagedType_U1__bool__MarshalAsUnmanagedType_U1__bool
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 15:04:55
опа! вот это здорово! спасибо!

второй вопрос еще актуален
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 28-11-2018, 15:06:59
а вот если проходить по BlockTable, то мне нужно открывать по ObjectId каждый btr и проверять что это внешняя ссылка?
второй вопрос еще актуален
А какие ещё есть варианты? Вроде как, иного пути нет.
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 15:16:03
А кто-то в теме спрашивал про слой? Как нибудь определись с тем, что тебе нужно.
мне нужно удалить то все! но если они лежат в заблокированном слое, то его нужно разблокировать сначала. а для этого узнать что за слой! так ведь?

а вот если проходить по BlockTable, то мне нужно открывать по ObjectId каждый btr и проверять что это внешняя ссылка?
Тут я бы рекомендовал запомнить состояние слоёв и все разблокировать, выполнить удаление внешних ссылок а затем восстановить состояние слоёв.
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 15:17:20
что то не нашел у btr соответствующих свойств, кроме статуса внешней ссылки. как определить что это внешняя ссылка(любая)? неужели перебирать все статусы в условии?
можно не отвечать.. понял
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 15:27:20
IsFromExternalReference
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 15:33:17
это не то же самое?
Код - C# [Выбрать]
  1. if (btrXRef.XrefStatus != XrefStatus.NotAnXref)
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 16:26:13
а вот сейчас я окончательно запутался.
попробовал просто найти все BlockTableRecord внешних ссылок и удалил. без обратки слоев. и он удалил даже в заблокированном!
так и долнжо быть? изначально он так не мог.
причем без этого
соответствующей опцией forceOpenOnLockedLayer
Название: Re: Удаление всех внешних ссылок
Отправлено: Дмитрий Загорулькин от 28-11-2018, 16:36:00
попробовал просто найти все BlockTableRecord внешних ссылок и удалил. без обратки слоев. и он удалил даже в заблокированном!
так и долнжо быть?
Ну так удалены же были определения блоков. Это не графические объекты, они не располагаются на слоях. А до этого, наверное, удалялись вставки блоков - это уже графические объекты, которые могут располагаться на слоях. Удивительно, что удаление определения блока при наличии в чертеже вставок происходит без ошибок. Я бы расценивал это как подарок от API :)
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 16:39:58
я и в прошлый раз "детачил" внешние ссылки, а не удалял вставки.. но как ты напоролся на ошибку из-за слоя...
может я опять что то путаю - не исключено
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 19:56:29
Я проверил этот код в AutoCAD 2019:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System.Collections.Generic;
  6.  
  7. #pragma warning disable 0618
  8.  
  9. // This line is not mandatory, but improves loading performances
  10. [assembly: CommandClass(typeof(Rivilis.ScanXrefs))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class ScanXrefs
  15.   {
  16.     [CommandMethod("RemoveAllXrefs")]
  17.     public void RemoveAllXrefs()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.       Editor ed = doc.Editor;
  22.       Database db = doc.Database;
  23.       List<ObjectId> idsXref = new List<ObjectId>();
  24.       using (BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead) as BlockTable)
  25.       {
  26.         foreach (ObjectId idBtr in bt)
  27.         {
  28.           using (BlockTableRecord btr = idBtr.Open(OpenMode.ForRead) as BlockTableRecord)
  29.           {
  30.             if (btr.IsFromExternalReference)
  31.               idsXref.Add(idBtr);
  32.           }
  33.         }
  34.       }
  35.       foreach (ObjectId idBtr in idsXref)
  36.         db.DetachXref(idBtr);
  37.     }
  38.   }
  39. }

Он удаляет все вставки внешних ссылок, а затем и описания блоков внешних ссылок, если вставки непосредственно в модели/листе. Но если они внутри блока, то мы видим сообщение:
Цитировать
Xref 1 has multiple references. Not detached.
Так что правильно сначала удалить все вставки внешних ссылок, а затем уже их "детачить" внешние ссылки.
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 20:23:51
Вот так должно быть универсальнее. Потестируй:

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System.Collections.Generic;
  6.  
  7. #pragma warning disable 0618
  8.  
  9. // This line is not mandatory, but improves loading performances
  10. [assembly: CommandClass(typeof(Rivilis.ScanXrefs))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class ScanXrefs
  15.   {
  16.     [CommandMethod("RemoveAllXrefs")]
  17.     public void RemoveAllXrefs()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.       Editor ed = doc.Editor;
  22.       Database db = doc.Database;
  23.       List<ObjectId> idsXref = new List<ObjectId>(); // Внешние ссылки
  24.       List<ObjectId> idsLocked = new List<ObjectId>(); // Блокированные слои
  25.       // Отбираем блокированные слои и сразу их разблокируем
  26.       using (LayerTable lt = db.LayerTableId.Open(OpenMode.ForRead) as LayerTable)
  27.       {
  28.         foreach (ObjectId idLay in lt)
  29.         {
  30.           using (LayerTableRecord ltr = idLay.Open(OpenMode.ForRead) as LayerTableRecord)
  31.           {
  32.             if (ltr.IsLocked)
  33.             {
  34.               ltr.UpgradeOpen();
  35.               ltr.IsLocked = false;
  36.               idsLocked.Add(idLay);
  37.             }
  38.           }
  39.         }
  40.       }
  41.       // Отбираем внешние ссылки
  42.       using (BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead) as BlockTable)
  43.       {
  44.         foreach (ObjectId idBtr in bt)
  45.         {
  46.           using (BlockTableRecord btr = idBtr.Open(OpenMode.ForRead) as BlockTableRecord)
  47.           {
  48.             if (btr.IsFromExternalReference)
  49.               idsXref.Add(idBtr);
  50.           }
  51.         }
  52.       }
  53.       // Удаляем внешние ссылки
  54.       foreach (ObjectId idBtr in idsXref)
  55.       {
  56.         using (BlockTableRecord btr = idBtr.Open(OpenMode.ForRead) as BlockTableRecord)
  57.         {
  58.           // Находим все вставки внешних ссылок и удаляем их
  59.           ObjectIdCollection idsBrefs = btr.GetBlockReferenceIds(false, true);
  60.           foreach (ObjectId idBref in idsBrefs)
  61.             using (DBObject bref = idBref.Open(OpenMode.ForWrite))
  62.               bref.Erase();
  63.         }
  64.         // Удаляем саму внешнюю ссылку
  65.         db.DetachXref(idBtr);
  66.       }
  67.       // Блокируем слои, которые были заблокированы до запуска команды
  68.       // но небыли удалены при удалении внешних ссылок
  69.       foreach (ObjectId idLay in idsLocked)
  70.           if (!idLay.IsErased)
  71.           using (LayerTableRecord ltr = idLay.Open(OpenMode.ForWrite) as LayerTableRecord)
  72.             ltr.IsLocked = true;
  73.     }
  74.   }
  75. }
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 20:32:31
Ну и по подсказке Дмитрий Загорулькин можно сократить код на сохранение/восстановление блокировки слоёв:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System.Collections.Generic;
  6.  
  7. #pragma warning disable 0618
  8.  
  9. // This line is not mandatory, but improves loading performances
  10. [assembly: CommandClass(typeof(Rivilis.ScanXrefs))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class ScanXrefs
  15.   {
  16.     [CommandMethod("RemoveAllXrefs")]
  17.     public void RemoveAllXrefs()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.       Editor ed = doc.Editor;
  22.       Database db = doc.Database;
  23.       List<ObjectId> idsXref = new List<ObjectId>(); // Внешние ссылки
  24.  
  25.       // Отбираем внешние ссылки
  26.       using (BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead) as BlockTable)
  27.       {
  28.         foreach (ObjectId idBtr in bt)
  29.         {
  30.           using (BlockTableRecord btr = idBtr.Open(OpenMode.ForRead) as BlockTableRecord)
  31.           {
  32.             if (btr.IsFromExternalReference)
  33.               idsXref.Add(idBtr);
  34.           }
  35.         }
  36.       }
  37.       // Удаляем внешние ссылки
  38.       foreach (ObjectId idBtr in idsXref)
  39.       {
  40.         using (BlockTableRecord btr = idBtr.Open(OpenMode.ForRead) as BlockTableRecord)
  41.         {
  42.           // Находим все вставки внешних ссылок и удаляем их
  43.           ObjectIdCollection idsBrefs = btr.GetBlockReferenceIds(false, true);
  44.           foreach (ObjectId idBref in idsBrefs)
  45.             // Открываем с учетом возможных блокированных слоёв
  46.             using (DBObject bref = idBref.Open(OpenMode.ForWrite,false,true))
  47.               bref.Erase();
  48.         }
  49.         // Удаляем саму внешнюю ссылку
  50.         db.DetachXref(idBtr);
  51.       }
  52.     }
  53.   }
  54. }

У меня работает.
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 22:20:03
Но если они внутри блока

Вы имеете ввиду именно блок? Не внутри другой внешней ссылки?
Если первое то не встречал такого.

Еще что примечательно, если перебирать XrefGraph, там хранятся удаленные внешние ссылки и тогда при попытке удалить вылетает исключение, при переборе BlockTable такой беды нет, поэтому я остановился на похожем на первый ваш вариант.
Название: Re: Удаление всех внешних ссылок
Отправлено: Александр Ривилис от 28-11-2018, 22:25:23
Вы имеете ввиду именно блок? Не внутри другой внешней ссылки?
Если первое то не встречал такого.
Именно в блоке. Запускаешь команду БЛОК (_BLOCK), выделяешь внешнюю ссылку (можешь еще что-то выбрать  - не важно). Вот у тебя вставка внешней ссылки в блоке. Вообще-то вложенность может быть любой.
Еще что примечательно, если перебирать XrefGraph, там хранятся удаленные внешние ссылки и тогда при попытке удалить вылетает исключение
Проверять нужно удалена или нет...
Название: Re: Удаление всех внешних ссылок
Отправлено: simson43 от 28-11-2018, 23:36:26
Ну да можно и так.
 Александр Ривилис, Дмитрий Загорулькин, Спасибо за ответы!