Перемещение объекта Ole2Frame во внешнем чертеже

Автор Тема: Перемещение объекта Ole2Frame во внешнем чертеже  (Прочитано 12433 раз)

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

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

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

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Добрый день, коллеги! Возникла следующая задача: переместить все примитивы в пространстве модели внешнего чертежа, не открывая в его в AutoCAD. Проблема заключается в том, что объекты Ole2Frame остаются на месте, причем остальные примитивы (отрезки, кривые, вхождения блоков и т.д.) перемещаются.
Заметил, что Ole2Frame удается переместить  только  в чертеже, открытом в AutoCAD.
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
  2. destDb.ReadDwgFile(pathDwg, FileOpenMode.OpenForReadAndAllShare, false, null); //читаем БД внешнего чертежа
  3. destDb.CloseInput(true);
  4.  
  5. using (Transaction destTr = destDb.TransactionManager.StartTransaction())
  6. {
  7.     ObjectId modelId = SymbolUtilityServices.GetBlockModelSpaceId(destDb); //ID пр-ва модели
  8.     BlockTableRecord destModel = (BlockTableRecord)destTr.GetObject(modelId, OpenMode.ForRead);
  9.  
  10.     foreach (ObjectId destId in destModel) //цикл по примитивам пр-ва модели
  11.     {
  12.         Entity destEnt = (Entity)destTr.GetObject(destId, OpenMode.ForWrite); //открываем примитив на редактирование
  13.        
  14.          //смещаем примитив на заданный вектор
  15.         destEnt.TransformBy(Matrix3d.Displacement("вектор_смещения"); //объект Ole2Frame не двигается :(          
  16.     }
  17.     destTr.Commit()
  18. }
  19.  
« Последнее редактирование: 06-05-2014, 13:09:49 от Александр Ривилис »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Приветствую на форуме!  :)
Уточни версию AutoCAD.
Попробуй перед этим кодом вставить:
Код - C# [Выбрать]
  1. Database curDb = HostApplicationServices.WorkingDatabase;
  2. HostApplicationServices.WorkingDatabase = destDb;
а после него
Код - C# [Выбрать]
  1. HostApplicationServices.WorkingDatabase = curDb;
Если не поможет, то приложи чертеж с парочкой линий и одним OLE-объектом. Отправлю вопрос ADN DevHelp.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Еще немного подумал. У примитива Ole2Frame есть свойство Position3d (угловые точки этого примитива). Так вот можно сделать отдельную обработку для этого типа примитива, меняя свойство Position3d (для каждой из его точек выполнить TransformBy). Не пробовал, но возможно это поможет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
foreach (ObjectId destId in destModel)
Маленькое замечание: я бы ещё добавил проверку на валидность, не уничтоженность, а так же на то, что перемещаемый объект находится не на заблокированном слое.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Так вот можно сделать отдельную обработку для этого типа примитива, меняя свойство Position3d (для каждой из его точек выполнить TransformBy)
Они-ль не ReadOnly? В смысле TransformBy к точке, в отличие от примитива, только возращает новую - которую надо куда-то деть.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
По поводу блокированного слоя я конечно не подумал, допустив, что этот код, когда этот же чертеж открыт в редакторе AutoCAD, у автора работает.
Но конечно нужно проверять.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Они-ль не ReadOnly?
В документации Read/Write. И в Object Browser тоже:

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Все прочитал не верно - подумал брать из Position3d Point3d и их трансформить...

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

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Коллеги, спасибо за идеи.  :)
Работаю в AutoCAD 2010 SP2 x64.
Попробуй перед этим кодом вставить:
Код - C# [Выбрать]
  1. Database curDb = HostApplicationServices.WorkingDatabase;
  2. HostApplicationServices.WorkingDatabase = destDb;
К сожалению, ни это, ни обработка свойства Position3d у объекта Ole2Frame не помогло. Все объекты располагаются на одном слое, он разблокирован, включен и т.д. (остальные же примитивы перемещаются). Все ObjectId примитивов пространства модели на валидность проверил.

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Все объекты располагаются на одном слое, он разблокирован, включен и т.д. (остальные же примитивы перемещаются).
Тогда наверное можно успокоиться - все в порядке - это баг...
« Последнее редактирование: 06-05-2014, 21:32:20 от Дима_ »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Подтверждаю такое поведение и  в AutoCAD 2015. Отправил в ADN DevHelp. Может подскажут как с этим бороться.
« Последнее редактирование: 07-05-2014, 01:28:26 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Можно конечно еще попробовать вариант через P/Invoke для метода AcDbOle2Frame::setLocation, но это заведомо привязка версии и разрядности AutoCAD и достаточно муторно. Так что подождем ответа из Autodesk.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Подтверждаю такое поведение и  в AutoCAD 2015. Отправил в ADN DevHelp. Может подскажут как с этим бороться.
Будем на это надеяться.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Пробовал использовать Ole2Frame.Position2d или Ole2Frame.Position3d?

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

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
Пробовал использовать Ole2Frame.Position2d или Ole2Frame.Position3d?
Сейчас попробовал изменить свойство Ole2Frame.Position2d - результата никакого. Свойство Position3d пробовал изменить ранее - о результате отписался (то же самое).

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Кстати, когда я проверял вариант с Ole2Frame.Position3d, то обратил внимание, что значения всех угловых точек (0,0,0), что крайне странно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Баг подтвердили в ADN DevHelp и передали команде разработчиков. Похоже никакого способа обойти его нет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Сколько "радостных" новостей в один день...

Отмечено как Решение Александр Ривилис 13-08-2015, 01:11:55

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
А решение было так близко. Нужно заменить
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
на
Код - C# [Выбрать]
  1. Database destDb = new Database(false, false);
Во всяком случае в AutoCAD 2015 это работает.
Наткнулся я на это решение, когда мне сообщили, что в чистом ObjectARX это вроде работает.
Когда я сделал отладочный код на C++:
Код - C++ [Выбрать]
  1. static void TransDb(LPCTSTR pathDwgInput, LPCTSTR pathDwgOutput, AcGeVector3d v)
  2. {
  3.         AcDbDatabase *destDb = new AcDbDatabase(false, true);
  4.         destDb->readDwgFile(pathDwgInput, AcDbDatabase::OpenMode::kForReadAndAllShare);
  5.         destDb->closeInput(false);
  6.         {
  7.                 AcDbObjectId modelId = acdbSymUtil()->blockModelSpaceId(destDb);
  8.                 AcDbBlockTableRecordPointer destModel(modelId, AcDb::kForRead);
  9.                 AcGeMatrix3d mat; mat.setToTranslation(v);
  10.                 if (destModel.openStatus() == Acad::eOk) {
  11.                         AcDbBlockTableRecordIterator *pIter = NULL;
  12.                         destModel->newIterator(pIter);
  13.                         if (pIter) {
  14.                                 for (; !pIter->done(); pIter->step()) {
  15.                                         AcDbObjectId eId;
  16.                                         if (pIter->getEntityId(eId) == Acad::eOk) {
  17.                                                 AcDbObjectPointer<AcDbEntity> pEnt(eId, AcDb::kForWrite);
  18.                                                 if (pEnt.openStatus() == Acad::eOk) {
  19.                                                         pEnt->transformBy(mat);
  20.                                                 }
  21.                                         }
  22.                                 }
  23.                                 delete pIter;
  24.                         }
  25.                 }
  26.                 destDb->saveAs(pathDwgOutput, true);
  27.         }
  28.         delete destDb;
  29. }
  30.  
  31. static void MyGroupMoveDb () {
  32.         TransDb(L"C:\\testOle2Frame.dwg",      // Input file
  33.                 L"C:\\testOle2Frame-new.dwg",  // Output file
  34.                 AcGeVector3d(100, 100, 0)     // Displacement
  35.         );
  36. }
Но код работал точно так же, как и на C#.  И только замена
Код - C++ [Выбрать]
  1.         AcDbDatabase *destDb = new AcDbDatabase(false, true);
на
Код - C++ [Выбрать]
  1.         AcDbDatabase *destDb = new AcDbDatabase(false, false);
принесла положительный результат.

Теперь напишу в ADN DevHelp об этом. Халтурщики. :)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 5
  • Карма: 0
А решение было так близко. Нужно заменить
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
на
Код - C# [Выбрать]
  1. Database destDb = new Database(false, false);
Действительно работает. Проверил на AutoCAD 2010 x64 SP2. И это не может не радовать :) Спасибо!

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Причина оказалась банально простой. Ole2Frame жестко завязан на документ (Document/AcApDocument/MFCDocument) и без него редактироваться не может. А конструктор:
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
создает базу без соответствующего документа.
Я не заметил разницы в скорости работы программы при двух вариантах работы конструктора, хотя второй вариант должен быть теоретически несколько медленнее.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение