Аналог команды INSERT

Автор Тема: Аналог команды INSERT  (Прочитано 6788 раз)

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

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

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Аналог команды INSERT
« : 08-01-2020, 00:02:13 »
Снова всех приветствую  8)
Как сделать аналог команды INSERT чтобы вставлялся блок из файла и его можно было ещё перемещать. Я думал, что надо копать в сторону jig, но вменяемой информации не нашёл. Я сделал вот так, всё работает, но нельзя указать координаты вручную, AutoCAD странно реагирует.
Код - C# [Выбрать]
  1.         [CommandMethod("lmxInsertBlock")]
  2.         public void lmxInsertBlock()
  3.         {
  4.             Database lxDatabase = Application.DocumentManager.MdiActiveDocument.Database;
  5.             Editor lxEditor = Application.DocumentManager.MdiActiveDocument.Editor;
  6.             BlockReference lxBlockReference;
  7.             ObjectId lxObjectID;
  8.             Point3d lxBlockInsert = Point3d.Origin;
  9.  
  10.             string FileName = "E:/A3_Form_1_Landscape.dwg";
  11.  
  12.             using (Transaction lxTransaction = lxDatabase.TransactionManager.StartTransaction())
  13.             {
  14.                 using (Database lxTempDatabase = new Database(false, true))
  15.                 {
  16.                     BlockTable lxBlockTable = lxTransaction.GetObject(lxDatabase.BlockTableId, OpenMode.ForWrite, false) as BlockTable;
  17.                     string BlockName = FileName.Replace("E:/", "").Replace(".dwg", "");
  18.                     lxTempDatabase.ReadDwgFile(FileName, System.IO.FileShare.Read, true, null);
  19.                     lxObjectID = lxDatabase.Insert(BlockName, lxTempDatabase, true);
  20.                     lxBlockReference = new BlockReference(lxBlockInsert, lxObjectID);
  21.                 }
  22.  
  23.                 BlockTableRecord lxBlockTableRecord = lxTransaction.GetObject(lxDatabase.CurrentSpaceId, OpenMode.ForWrite, true, true) as BlockTableRecord;
  24.                 lxBlockTableRecord.AppendEntity(lxBlockReference);
  25.                 lxTransaction.AddNewlyCreatedDBObject(lxBlockReference, true);
  26.  
  27.                 PromptSelectionResult lxSelectionResult = lxEditor.SelectLast();
  28.  
  29.                 if (lxSelectionResult.Status == PromptStatus.OK)
  30.                 {
  31.                     PromptPointResult lxPointResult = lxEditor.Drag(lxSelectionResult.Value, "\nSelect object location: ",
  32.                         delegate (Point3d lxPoint, ref Matrix3d lxMatrix)
  33.                         {
  34.                             if (lxBlockInsert == lxPoint)
  35.                                 return SamplerStatus.NoChange;
  36.                             else
  37.                             {
  38.                                 lxMatrix = Matrix3d.Displacement(lxBlockInsert.GetVectorTo(lxPoint));
  39.                             }
  40.                             return SamplerStatus.OK;
  41.                         }
  42.                       );
  43.  
  44.                     if (lxPointResult.Status == PromptStatus.OK)
  45.                     {
  46.                         Matrix3d lxMatrix = Matrix3d.Displacement(lxBlockInsert.GetVectorTo(lxPointResult.Value));
  47.                         lxBlockReference.TransformBy(lxMatrix);
  48.                         lxTransaction.Commit();
  49.                     }
  50.                 }
  51.             }
  52.         }

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #1 : 08-01-2020, 00:12:35 »
Я думал, что надо копать в сторону jig
Правильно думал.
но вменяемой информации не нашёл.
Плохо искал. И у нас на форуме есть масса примеров. Например: https://adn-cis.org/forum/index.php?topic=7545.0
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #2 : 08-01-2020, 00:35:59 »
А если использовать Editor.Drag, то нужно разделить транзакции. В первой транзакции создаёт вставку блока, а во второй её тащим.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #3 : 08-01-2020, 01:51:00 »
А если использовать Editor.Drag, то нужно разделить транзакции. В первой транзакции создаёт вставку блока, а во второй её тащим.
А зачем так делать?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #4 : 08-01-2020, 02:51:29 »
А зачем так делать?
Потому что пока не завершена первая транзакция блок еще не вставлен в базу.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #5 : 08-01-2020, 03:02:01 »
Большая статья с примером использования JIG для вставки блока: https://through-the-interface.typepad.com/through_the_interface/2009/03/jigging-an-autocad-block-with-attributes-using-net.html (в том примере блок уже добавлен в активную базу).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #6 : 08-01-2020, 12:36:57 »
А зачем так делать?
Потому что пока не завершена первая транзакция блок еще не вставлен в базу.
Вот эту часть транзакций я понимаю, что транзакции для работы с базой чертежа. А зачем открывать транзакцию, если надо перемещать объект?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #7 : 08-01-2020, 15:22:58 »
А зачем открывать транзакцию, если надо перемещать объект?
Для того чтобы можно было вызвать его итоговое перемещение ( lxBlockReference.TransformBy(lxMatrix); )
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #8 : 08-01-2020, 16:01:05 »
А зачем открывать транзакцию, если надо перемещать объект?
Для того чтобы можно было вызвать его итоговое перемещение ( lxBlockReference.TransformBy(lxMatrix); )
Значит у меня план действий такой?
1. Открываю транзакцию для записи
2. Добавляю блок в базу чертежа
3. Закрываю транзакцию
4. Открываю транзакцию для чтения
5. Получаю ссылку на этот блок
6. Перемещаю блок как мне надо
7. Закрываю транзакцию

Отмечено как Решение Lemieux 08-01-2020, 16:45:54

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #9 : 08-01-2020, 16:18:48 »
Значит у меня план действий такой?
Ну если не считать, что транзакция не "открывается для чтения", а для чтения открывается объект/примитив AutoCAD. И открывать BlockReference нужно для записи, так как ты его собираешься модифицировать (перемещать).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #10 : 08-01-2020, 16:46:18 »
Значит у меня план действий такой?
Ну если не считать, что транзакция не "открывается для чтения", а для чтения открывается объект/примитив AutoCAD. И открывать BlockReference нужно для записи, так как ты его собираешься модифицировать (перемещать).
Теперь понятна логика транзакций. Большое спасибо  :)

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #11 : 23-01-2020, 18:52:38 »
Кто может объяснить как определяется что "BlockTable" является списком, где об этом говорится?
И почему, вставляя блок кодом ниже, у блока не распознаются атрибуты? Но если его вставлять из меню, то всё нормально вставляется.
Код - C# [Выбрать]
  1. [CommandMethod("lmxInsertBlock")]
  2.         public void lmxInsertBlock()
  3.         {
  4.             Document lxDocument = Application.DocumentManager.MdiActiveDocument;
  5.             Database lxDatabase = Application.DocumentManager.MdiActiveDocument.Database;
  6.             Editor lxEditor = Application.DocumentManager.MdiActiveDocument.Editor;
  7.             ObjectId lxObjectID;
  8.  
  9.             string FileName = "E:/A3.dwg";
  10.  
  11.             using (Transaction lxTransaction = lxDatabase.TransactionManager.StartTransaction())
  12.             {
  13.                 using (Database lxTempDatabase = new Database(false, true))
  14.                 {
  15.                     BlockTable lxBlockTable = lxTransaction.GetObject(lxDatabase.BlockTableId, OpenMode.ForWrite, false) as BlockTable;
  16.                     string BlockName = FileName.Replace("E:/", "").Replace(".dwg", "");
  17.                     if (!lxBlockTable.Has(BlockName))
  18.                     {
  19.                         lxTempDatabase.ReadDwgFile(FileName, System.IO.FileShare.Read, true, null);
  20.                         lxObjectID = lxDatabase.Insert(BlockName, lxTempDatabase, true);
  21.                     }
  22.                     else
  23.                     {
  24.                         lxObjectID = lxBlockTable[BlockName];
  25.                     }
  26.                 }
  27.  
  28.                 lxTransaction.Commit();
  29.             }
  30.  
  31.             using (Transaction lxTransaction = lxDatabase.TransactionManager.StartTransaction())
  32.             {
  33.                 Point3d lxBlockInsertPoint = Point3d.Origin;
  34.                 //Point3d lxBlockInsertPoint = new Point3d(0, 0, 0);
  35.                 BlockTable lxBlockTable = lxTransaction.GetObject(lxDatabase.BlockTableId, OpenMode.ForRead) as BlockTable;
  36.                 BlockReference lxBlockReference = new BlockReference(lxBlockInsertPoint, lxObjectID);
  37.                 BlockEntityJig lxJig = new BlockEntityJig(lxBlockReference);
  38.                 lxEditor.Drag(lxJig);
  39.                 BlockTableRecord lxBlockTableRecord = lxTransaction.GetObject(lxBlockTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
  40.                 lxBlockTableRecord.AppendEntity(lxJig.GetEntity());
  41.                 lxTransaction.AddNewlyCreatedDBObject(lxJig.GetEntity(), true);
  42.                 //lxDocument.TransactionManager.QueueForGraphicsFlush();
  43.  
  44.                 lxTransaction.Commit();
  45.             }
  46.         }
  47.  
  48. class BlockEntityJig : EntityJig
  49.         {
  50.             Point3d mCenterPt, mActualPoint;
  51.  
  52.             public BlockEntityJig(BlockReference br) : base(br)
  53.             {
  54.                 mCenterPt = br.Position;
  55.             }
  56.  
  57.             protected override SamplerStatus Sampler(JigPrompts prompts)
  58.             {
  59.                 JigPromptPointOptions jigOpts = new JigPromptPointOptions();
  60.                 jigOpts.UserInputControls = UserInputControls.Accept3dCoordinates;
  61.                 jigOpts.UserInputControls = UserInputControls.NoZeroResponseAccepted;
  62.                 jigOpts.UserInputControls = UserInputControls.NoNegativeResponseAccepted;
  63.  
  64.                 jigOpts.Message = "\nEnter insert point: ";
  65.  
  66.                 PromptPointResult dres = prompts.AcquirePoint(jigOpts);
  67.  
  68.                 if (mActualPoint == dres.Value)
  69.                 {
  70.                     return SamplerStatus.NoChange;
  71.                 }
  72.                 else
  73.                 {
  74.                     mActualPoint = dres.Value;
  75.                 }
  76.                 return SamplerStatus.OK;
  77.             }
  78.  
  79.             protected override bool Update()
  80.             {
  81.                 mCenterPt = mActualPoint;
  82.                 try
  83.                 {
  84.                     ((BlockReference)Entity).Position = mCenterPt;
  85.                 }
  86.                 catch (System.Exception)
  87.                 {
  88.                     return false;
  89.                 }
  90.                 return true;
  91.             }
  92.  
  93.             public Entity GetEntity()
  94.             {
  95.                 return Entity;
  96.             }
  97.         }

/* Пользуйся  спойлером только для больших программ (> 300 строк). Содержимое спойлера не видно незарегистрированным на форуме и не индексируется поисковыми системами. Александр Ривилис */
« Последнее редактирование: 23-01-2020, 21:41:28 от Александр Ривилис »

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #12 : 23-01-2020, 20:29:52 »
ё моё, если я правильно понимаю, то при при вставке блока нужно ещё брать атрибуты из описания блока и делать из них AttributeReference? Если это так, то зачем так сделали?
Но первый вопрос всё ещё очень интересен.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Аналог команды INSERT
« Ответ #13 : 23-01-2020, 21:38:24 »
ё моё, если я правильно понимаю, то при при вставке блока нужно ещё брать атрибуты из описания блока и делать из них AttributeReference? Если это так, то зачем так сделали?
1. Правильно понимаешь.
2. Так решили в Autodesk.
Кто может объяснить как определяется что "BlockTable" является списком, где об этом говорится?
Списком??? Скорее уж таблицей, контейнером, массивом...
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ****
  • Сообщений: 384
  • Карма: 21
Re: Аналог команды INSERT
« Ответ #14 : 23-01-2020, 22:33:09 »
Про спойлер понял :)

2. Так решили в Autodesk.
А Вы не знаете почему они так решили, что о таком механизме можно догадаться только перелопачивая хелп или из опыта других людей?

Списком??? Скорее уж таблицей, контейнером, массивом...
Вот Вы как узнали, что можно применять такую конструкцию -
Код - C# [Выбрать]
  1. BlockTable["BlockName"]
, чтобы получить ObjectID?

Например я понял из примеров, но нигде в хелпе я не нашёл упоминания о том, что возвращается "массив", и что к объектам этого массива можно получать доступ по имени объекта.
Мне почему это интересно, я просто хочу понять логику разработки приложений на .NET и как работает AutoCAD.