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

ADN Club => AutoCAD .NET API => Тема начата: Korben Dallas от 06-05-2014, 11:08:46

Название: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Korben Dallas от 06-05-2014, 11:08:46
Добрый день, коллеги! Возникла следующая задача: переместить все примитивы в пространстве модели внешнего чертежа, не открывая в его в 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.  
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 06-05-2014, 13:22:42
Приветствую на форуме!  :)
Уточни версию AutoCAD.
Попробуй перед этим кодом вставить:
Код - C# [Выбрать]
  1. Database curDb = HostApplicationServices.WorkingDatabase;
  2. HostApplicationServices.WorkingDatabase = destDb;
а после него
Код - C# [Выбрать]
  1. HostApplicationServices.WorkingDatabase = curDb;
Если не поможет, то приложи чертеж с парочкой линий и одним OLE-объектом. Отправлю вопрос ADN DevHelp.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 06-05-2014, 13:29:44
Еще немного подумал. У примитива Ole2Frame есть свойство Position3d (угловые точки этого примитива). Так вот можно сделать отдельную обработку для этого типа примитива, меняя свойство Position3d (для каждой из его точек выполнить TransformBy). Не пробовал, но возможно это поможет.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Андрей Бушман от 06-05-2014, 13:38:50
foreach (ObjectId destId in destModel)
Маленькое замечание: я бы ещё добавил проверку на валидность, не уничтоженность, а так же на то, что перемещаемый объект находится не на заблокированном слое.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Дима_ от 06-05-2014, 13:47:32
Так вот можно сделать отдельную обработку для этого типа примитива, меняя свойство Position3d (для каждой из его точек выполнить TransformBy)
Они-ль не ReadOnly? В смысле TransformBy к точке, в отличие от примитива, только возращает новую - которую надо куда-то деть.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 06-05-2014, 13:48:01
По поводу блокированного слоя я конечно не подумал, допустив, что этот код, когда этот же чертеж открыт в редакторе AutoCAD, у автора работает.
Но конечно нужно проверять.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 06-05-2014, 13:48:25
Они-ль не ReadOnly?
В документации Read/Write. И в Object Browser тоже:
(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fimg-fotki.yandex.ru%2Fget%2F4705%2F7842324.0%2F0_d6ec5_4c041034_orig.png&hash=ebb27519a827ed0060d24294ae9c5458) (http://img-fotki.yandex.ru/get/4705/7842324.0/0_d6ec4_6a545562_orig.png)
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Дима_ от 06-05-2014, 13:53:54
Все прочитал не верно - подумал брать из Position3d Point3d и их трансформить...
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Korben Dallas от 06-05-2014, 16:22:03
Коллеги, спасибо за идеи.  :)
Работаю в AutoCAD 2010 SP2 x64.
Попробуй перед этим кодом вставить:
Код - C# [Выбрать]
  1. Database curDb = HostApplicationServices.WorkingDatabase;
  2. HostApplicationServices.WorkingDatabase = destDb;
К сожалению, ни это, ни обработка свойства Position3d у объекта Ole2Frame не помогло. Все объекты располагаются на одном слое, он разблокирован, включен и т.д. (остальные же примитивы перемещаются). Все ObjectId примитивов пространства модели на валидность проверил.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Дима_ от 06-05-2014, 17:26:25
Все объекты располагаются на одном слое, он разблокирован, включен и т.д. (остальные же примитивы перемещаются).
Тогда наверное можно успокоиться - все в порядке - это баг...
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 07-05-2014, 01:08:41
Подтверждаю такое поведение и  в AutoCAD 2015. Отправил в ADN DevHelp. Может подскажут как с этим бороться.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 07-05-2014, 01:36:43
Можно конечно еще попробовать вариант через P/Invoke для метода AcDbOle2Frame::setLocation, но это заведомо привязка версии и разрядности AutoCAD и достаточно муторно. Так что подождем ответа из Autodesk.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Korben Dallas от 07-05-2014, 08:59:55
Подтверждаю такое поведение и  в AutoCAD 2015. Отправил в ADN DevHelp. Может подскажут как с этим бороться.
Будем на это надеяться.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Андрей Бушман от 07-05-2014, 09:16:29
Пробовал использовать Ole2Frame.Position2d или Ole2Frame.Position3d?
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Korben Dallas от 07-05-2014, 11:58:01
Пробовал использовать Ole2Frame.Position2d или Ole2Frame.Position3d?
Сейчас попробовал изменить свойство Ole2Frame.Position2d - результата никакого. Свойство Position3d пробовал изменить ранее - о результате отписался (то же самое).
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 07-05-2014, 18:37:27
Кстати, когда я проверял вариант с Ole2Frame.Position3d, то обратил внимание, что значения всех угловых точек (0,0,0), что крайне странно.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 14-05-2014, 18:19:20
Баг подтвердили в ADN DevHelp и передали команде разработчиков. Похоже никакого способа обойти его нет.
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Андрей Бушман от 14-05-2014, 18:22:10
Сколько "радостных" новостей в один день...
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 14-05-2014, 20:20:59
А решение было так близко. Нужно заменить
Код - 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 об этом. Халтурщики. :)
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Korben Dallas от 15-05-2014, 10:41:15
А решение было так близко. Нужно заменить
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
на
Код - C# [Выбрать]
  1. Database destDb = new Database(false, false);
Действительно работает. Проверил на AutoCAD 2010 x64 SP2. И это не может не радовать :) Спасибо!
Название: Re: Перемещение объекта Ole2Frame во внешнем чертеже
Отправлено: Александр Ривилис от 15-05-2014, 20:57:52
Причина оказалась банально простой. Ole2Frame жестко завязан на документ (Document/AcApDocument/MFCDocument) и без него редактироваться не может. А конструктор:
Код - C# [Выбрать]
  1. Database destDb = new Database(false, true);
создает базу без соответствующего документа.
Я не заметил разницы в скорости работы программы при двух вариантах работы конструктора, хотя второй вариант должен быть теоретически несколько медленнее.