Связь между объектами чертежа. Есть ли какие-нибудь инструменты?

Автор Тема: Связь между объектами чертежа. Есть ли какие-нибудь инструменты?  (Прочитано 64672 раз)

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Здравствуйте!
Мне нужно связать между собой два объекта чертежа. Точнее один объект привязать к другому. Это объекты вертикального решения, но ничто "чисто автокадовское" им не чуждо, поэтому спрашиваю тут.
В основном, нужно чтобы при обращении к объекту который привязан (объект №2) всегда можно было быстро и однозначно определить объект, к которому он привязан (объект №1). Предполагаю, что впоследствии захочется чтобы при модификации объекта №1, объект №2 также изменял свое положение и при удалении объекта №1, объект №2 также нужно будет удалять.
Мне думается, что больше всего мне подойдет вариант такой: поместить в расширенные данные (РД) объекта №2 хендл объекта №1. Но если сделать только это, будет накладно отслеживать изменения объекта №1. Тогда, нужно еще в РД объекта №1 сохранить хендл объекта №2. А так как к объекту №1 может быть привязано несколько объектов, плюс, может быть, в дальнейшем понадобится их РД еще для чего-нибудь использовать, то структура их РД может получиться довольно сложной, чего мне не хочется.
В общем, вопрос такой: может быть есть какой-то другой механизм в API, который позволяет сделать постоянную связь между объектами без использования РД? Или же использование РД в этом случае будет оптимальным вариантом?
Спасибо.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Можно конечно и через расширенные данные, НО(!!!) что делать если:
1) один из объектов удалили?
2) один или оба объекта скопировали в пределах чертежа - какие теперь должны быть метки у новых объектов и как их присвоить?
3) один из объектов скопировали в другой чертеж что делать со вторым?
Задача очень сложная и скорее всего средствами AutoCAD .NET API в полном объеме нерешаемая.
Если речь идет не об объектах, а о примитивах, то можно подумать о группах. Но это тоже не полноценное решение, т.к. группы не копируются в другой чертеж как группы и могут быть проблемы с обычными операциями AutoCAD, когда не нужно производить действие сразу с обоими примитивами (например, _MOVE)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да, вопросов возникает сразу масса...
Пока придумал проводить обработку на основе взаимного положения объектов в модели - если один объект на другом (определяю геометрическими вычислениями), то считаю их связанными. Попробую обкатать такой вариант. Если быстродействие будет хромать - придется дальше развивать эту тему.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Можно конечно и через расширенные данные, НО(!!!) что делать если:
1) один из объектов удалили?
2) один или оба объекта скопировали в пределах чертежа - какие теперь должны быть метки у новых объектов и как их присвоить?
3) один из объектов скопировали в другой чертеж что делать со вторым?
Задача очень сложная и скорее всего средствами AutoCAD .NET API в полном объеме нерешаемая.
Если речь идет не об объектах, а о примитивах, то можно подумать о группах. Но это тоже не полноценное решение, т.к. группы не копируются в другой чертеж как группы и могут быть проблемы с обычными операциями AutoCAD, когда не нужно производить действие сразу с обоими примитивами (например, _MOVE)

Если оперировать хэндлами  или идентификаторами (с последующим их сохранением в виде хэндлов при закрытии чертежа), то на мой взгляд всё не так уж и страшно. В общих чертах так:
Код - C# [Выбрать]
  1.   internal interface ILinksInfo {
  2.     /// <summary>
  3.     /// Хэндлы объектов, которые ссылаются на
  4.     /// данный объект.
  5.     /// </summary>
  6.     List<Db.Handle> BottomHandles { get; }
  7.     /// <summary>
  8.     /// Хэндлы объектов, на которые ссылается
  9.     /// данный объект.
  10.     /// </summary>
  11.     List<Db.Handle> TopHandles { get; }
  12.   }
  13.  
  14.   /// <summary>
  15.   /// Базовая реализация интерфейса ILinksInfo
  16.   /// </summary>
  17.   [Serializable]
  18.   internal class LinksInfo : ILinksInfo {
  19.  
  20.     List<Db.Handle> bottomHandles;
  21.     List<Db.Handle> topHandles;
  22.  
  23.     public List<Db.Handle> BottomHandles {
  24.       get { return bottomHandles; }
  25.     }
  26.  
  27.     public List<Db.Handle> TopHandles {
  28.       get { return topHandles; }
  29.     }
  30.   }
  31.  
  32.   /// <summary>
  33.   /// Диспетчер ссылок для конкретной Database.
  34.   /// </summary>
  35.   internal sealed class LinksDispatcher :
  36.     IDisposable {
  37.     Dictionary<Db.Handle, List<ILinksInfo>> dict;
  38.  
  39.     internal Dictionary<Db.Handle,
  40.       List<ILinksInfo>> Dictionary {
  41.       get { return dict; }
  42.       set { dict = value; }
  43.     }
  44.     Db.Database db = null;
  45.  
  46.     public Db.Database Database {
  47.       get { return db; }
  48.       private set { db = value; }
  49.     }
  50.  
  51.     public LinksDispatcher(Db.Database _db) {
  52.       Database = _db;
  53.  
  54.       // Проверяем, хранится ли в Database наша
  55.       // информация о связях.
  56.       if(LinkInfoExists(Database)) {
  57.         // Если хранится, то читаем её.
  58.         dict = ReadLinkInfo(Database);
  59.         // Проверяем целостность информации:
  60.         // объекты указанных хэндлов существуют,
  61.         // корректны и не удалены. Те, которые не
  62.         // соотвтетствуют - убираем из структуры.
  63.         dict = CheckInfo(Database, dict);
  64.       }
  65.       else {
  66.         // Если не хранится - создаём новую
  67.         // структуру для её хранения.
  68.         dict = CreateDictInfo(Database);
  69.       }
  70.  
  71.       // Регистрируемся на интересующие нас
  72.       // события
  73.       Database.ObjectAppended += Database_ObjectAppended;
  74.       Database.ObjectErased += Database_ObjectErased;
  75.       Database.ObjectModified += Database_ObjectModified;
  76.     }
  77.  
  78.     void Database_ObjectModified(object sender,
  79.       Db.ObjectEventArgs e) {
  80.       throw new NotImplementedException();
  81.     }
  82.  
  83.     void Database_ObjectErased(object sender,
  84.       Db.ObjectErasedEventArgs e) {
  85.       throw new NotImplementedException();
  86.     }
  87.  
  88.     void Database_ObjectAppended(object sender,
  89.       Db.ObjectEventArgs e) {
  90.       throw new NotImplementedException();
  91.     }
  92.  
  93.     // Генерируем новую структуру, предназначенную
  94.     // для хранения информации о связях.
  95.     private Dictionary<Db.Handle,
  96.       List<ILinksInfo>> CreateDictInfo(
  97.       Db.Database Database) {
  98.  
  99.       Dictionary<Db.Handle,
  100.         List<ILinksInfo>> dict =
  101.         new Dictionary<Db.Handle,
  102.           List<ILinksInfo>>();
  103.  
  104.       for(Int64 i = db.BlockTableId.Handle
  105.            .Value; i < db.Handseed.Value; i++) {
  106.         Db.ObjectId id = Db.ObjectId.Null;
  107.         Db.Handle h = new Db.Handle(i);
  108.  
  109.         Boolean result = db.TryGetObjectId(h,
  110.           out id) && !id.IsNull && id.IsValid
  111.           && !id.IsErased &&
  112.           !id.IsEffectivelyErased;
  113.  
  114.         if(result)
  115.           dict.Add(new Db.Handle(i),
  116.             new List<ILinksInfo>());
  117.       }
  118.       return dict;
  119.     }
  120.  
  121.     // Проверяем целостность информации:
  122.     // объекты указанных хэндлов существуют,
  123.     // корректны и не удалены. Те, которые не
  124.     // соотвтетствуют - убираем из структуры.
  125.     private Dictionary<Db.Handle,
  126.       List<ILinksInfo>> CheckInfo(
  127.       Db.Database Database,
  128.       Dictionary<Db.Handle, List<ILinksInfo>>
  129.       dict) {
  130.       throw new NotImplementedException();
  131.     }
  132.  
  133.     // Читаем из Database ранее нами сохранённую
  134.     // информацию о связях.
  135.     private Dictionary<Db.Handle,
  136.       List<ILinksInfo>> ReadLinkInfo(
  137.       Db.Database Database) {
  138.       throw new NotImplementedException();
  139.     }
  140.  
  141.     // Проверка на то, хранится ли уже в Database
  142.     // наша информация о связях.
  143.     private bool LinkInfoExists(
  144.       Db.Database Database) {
  145.       throw new NotImplementedException();
  146.     }
  147.  
  148.  
  149.     public void Dispose() {
  150.       // Сохраняем в базу данных информацию о связях.
  151.       SaveLinkInfo(Database);
  152.     }
  153.  
  154.     // Сохраняем в базу данных информацию о связях.
  155.     private void SaveLinkInfo(Db.Database Database) {
  156.       throw new NotImplementedException();
  157.     }
  158.   }

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Андрей. Что делать с моим пунктом 2) и как это обрабатывается указанным кодом?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Цитировать
2) один или оба объекта скопировали в пределах чертежа - какие теперь должны быть метки у новых объектов и как их присвоить?
Андрей. Что делать с моим пунктом 2) и как это обрабатывается указанным кодом?
Скопированный объект содержит те же элементы в TopHandles. Список BottomHandles очищается, поскольку на новый объект ещё никто не завязывался.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Иногда работаю в ADT. Там есть "составные объекты", стены и отверстия; линия сечения и обозначение сечения и др. Поведение отверстий и обозначений сечений вполне похоже на описанное Дмитрием. Связаны эти объекты "Якорями". Я с ними "работал" очень давно и на VBA. Ближайшее что нашел под .NET тут: http://www.theswamp.org/index.php?topic=43114.msg483415#msg483415 . Возможно это поможет.


Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Boxa, я в Civil работаю. Там тоже есть различные коннекторы и прочие виды связи между объектами. Но стандартных мало, понадобилось сделать вот такую дополнительную связь.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Предложение Андрея половинчатое. Потребуется подмена кучи команд для то, чтобы при копировании новых объектов появлялись правильные новые "перекрестные ссылки". Да и на события типа Database.BeginDeepClone, Database.EndDeepClone  и т.д. придется подписываться и в них обрабатывать метки...
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ну это один из вариантов организации хранения связей и некоторые методы для их обработки. Конечно же, придется написать еще с десяток-другой дополнительных методов и молиться, что все предусмотрели... Так что пока этот путь оставлю про запас.

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

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

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
1)   Я в своей работе использую расширенные данные (РД) Xdata для связи объектов между собой.
Если к примеру я обращаюсь к одному объекту, то в РД одного храню Handle другого.
В работе ни каких сложностей не вижу.

2)   Сохранять связь между объектами по Handle имеет только один недостаток, в том, что при копировании объекта в другой чертеж Handle будет другой и связь будет разорвана,
что еще хуже связь может быть установлена с другим объектом,
т.к. есть вероятность, что в другом файле Handle может совпадать.
 Что касается одного файла, Handle в уникальные.

3)   К решению этой задачи нужно подходить предметно.
Для стабильной работы с несколькими файлами DWG нужно комбинировать Xdata и Xrecord
в Xdata -  хранить Handle примитива.
в Xrecord нужно хранить уникальный номер проектного файла
Уникальные номера должна присваивать внешняя программа (Сервер проектов)
Т.е. получается что объект идентифицируется однозначно (номер файла + Handle)
Если примитив вставляется из одного файла в другой, то он имеет в Xdata другой номер файла или не имеет
его вовсе, то нужно сделать команду, которая привяжет этот примитив к данному dwg  файлу
т.е. запишет в Xdata номер файла. Что касается ссылок между объектами,
то нужно делать команду обновления ссылок учитывая ссылки по старым Handle.
Т.е., когда в проект включается новый файл, то ему должен быть присвоен уникальный номер
 и другая дополнительная информация характерная для объекта проектирования (Заказа)
Но тут есть тоже проблема, когда пользователь начнет копировать файлы, то у него будут файлы
с одинаковыми внутренними номерами, тогда системы должна среагировать на это и
присвоить новый уникальный номер, как некий вариант проектного решения.   

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1097
  • Карма: 172
Я бы не стал делать ставку на РД:
1. Всего 16 кб данных. И этот объем делится на все приложения.
2. Слишком легко снести / отредактировать
Будь у меня выбор, я бы остановился на словарях и словарных записях.

Есть еще один момент - вставка файла внутрь другого как внешней ссылки (про вставку как блок или внедрение ссылки я уже не упоминаю). Это как вариант, который тоже придется рассматривать и предусматривать.
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Алексей, скажи а что 16К для XData этого, что для одного примитива мало что ли?
Или ты думаешь, что 16K отводится на всю базу примитивов?

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Главный вопрос состоит в том чтобы связать два примитива между
собой настолько надежно, то бы эта связь оставалась стабильной при любых
необдуманных и обдуманных действиях пользователей.

Для того чтобы реально решить эту задачу.
Нужно сначала четко составить список всех возможных
"легальных" (т.е. в рамках технологии проектирования) действий пользователя.
И список "ошибочных" действий пользователя.
Я так считаю. Что если мы хотим чтобы работало стабильно и
без сбоев, то система должна строится как бы "над AutoCAD"
но и в тоже время "в связи с AutoCAD".

 
« Последнее редактирование: 11-06-2014, 23:29:58 от IdeaSoft »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
что бы связать два примитива между
собой на столько надежно, то бы эта связь оставалась стабильной при любых
необдуманных и обдуманных действиях пользователей
ха-ха три раза.
хотим чтобы работало стабильно и без сбоев
В ту же корзину.

P.S. Не забывай - это же AutoCAD... "Стабильность и без сбоев" нам может только сниться. Это тебе не реляционная база данных.

P.S.2 "что бы" и "на столько" пишутся слитно (глаза режет).

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Думаю вот, что может у инициатора данной темы попросить четкие
требования к этой задачи и тогда из этих требований уже выработать
конепт проекта. После чего приступить к решению задачи.
Хотя бы выяснить систему связей какие они
- двунаправленные
- однонаправленные
- разветвленные
или все варианта может еще какие варианты   
Потому как на конкретном примере думается легче.
Я вот к примеру решал подобную задачу 2005 году в MicroStation V8
связей объектов для строительства наружных сетей.
 

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Да ты прав "чтобы" пишется в месте но бывают случаи по смыслу что бы пишется отдельно если между что и бы можно вставить слово.
"настолько" тоже в этом случае пишется вместе , а если писать в контексте "...на столько частей.." то раздельно.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
я сделал замечание с учётом контекста.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Однако! Это я по поводу грамматических изысканий и (!!!) насмешек над стабильностью AutoCAD. Первый вопрос давайте обсуждать где-нибудь здесь: http://adn-cis.org/forum/index.php?board=23.0
Ну а второе вообще не подлежит обсуждению! Обсуждать можно конкретные баги.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Думаю вот, что может у инициатора данной темы попросить четкие
требования к этой задачи и тогда из этих требований уже выработать
конепт проекта. После чего приступить к решению задачи.
Хотя бы выяснить систему связей какие они
- двунаправленные
- однонаправленные
- разветвленные
или все варианта может еще какие варианты   
Потому как на конкретном примере думается легче.
Я вот к примеру решал подобную задачу 2005 году в MicroStation V8
связей объектов для строительства наружных сетей.
Меня интересовали не пути решения этой задачи, а есть ли стандартный инструмент в API для этого.
Конечно, использовать для хранения связи можно хоть РД, хоть ExtensionDictionary, хоть NOD, хоть любое другое место уже вне чертежа или комбинацию этих вариантов. Но у каждого из них есть недостатки, которые нужно будет чем-то прикрывать, подстраховываться и перестраховываться от различных ситуаций. Все ситуации заранее очень сложно предусмотреть, всегда есть риск упустить что-то важное.
Честно говоря, я уже не помню, зачем мне нужно было объекты связывать. Но, оценив объем работы, который придется проделать, я пошел по другому пути, без такой связи. В итоге меня это полностью устроило.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
И снова приходится возвращаться к этому вопросу. Причем, задача из разряда "классических":
Есть какая-то деталь. Данные о детали находятся в базе данных. На чертеже деталь отображается в виде блока (INSERT), в РД которого есть ссылка на ID записи в базе данных.
К этой детали ставится выноска. В выноске нужно отобразить информацию, которая вычисляются на основе данных о детали из базы и других данных чертежа (к примеру - порядковый номер детали в ведомости деталей). Выноска - это объект "мультивыноска"(MLEADER). Актуализация информации выполняется запуском отдельной команды.
Я придумал три варианта решения этой задачи:
1. В РД выноски помещается ссылка на ID записи о детали в базе данных.
Из плюсов такого подхода - если пользователь аккуратно пользуется стандартными инструментами редактирования (например, копирует блоки вместе с выносками), то такая "связь" не нарушается.
Из минусов - если редактировать чертеж неаккуратно, то выноски могут указывать на пустое место или вообще на другой объект чертежа, т.к. они никак не связаны с блоком, на который должны указывать. Это может привести к ошибкам на чертеже.
2. Разработать свою связь между объектами блока и выноски (как вариант - на основе тех идей, что высказывались ранее в этой теме).
Из плюсов - Если предусмотреть все варианты развития событий, то возможность возникновения ошибки на чертеже будет сведена к минимуму.
Из минусов - нужно проработать большое количество возможных ситуаций при различных действиях пользователей и есть риск, что все равно что-то останется неучтенным. И самый большой минус - при отсутствии подгруженного приложения, редактировать чертеж категорически нельзя! Иначе связи могут быть потеряны.
3. Вычислять геометрически взаимное расположение блоков и выносок и на основе этих данных делать заключение о связи между ними.
Из плюсов - никаких ограничений по использованию стандартных инструментов автокада.
Из минусов - сложно придумать алгоритм, гарантирующий на 100%, что будет установлено какая выноска на какой блок указывает. На насыщенных схемах (где одна деталь устанавливается поверх другой) есть риск, что связь будет определена неверно и появятся ошибки на чертеже.
Прошу оценить эти варианты с вашей точки зрения. Чему бы вы отдали предпочтение? Может будут еще варианты, которые я упустил?

Оффлайн German

  • ADN Club
  • **
  • Сообщений: 84
  • Карма: 13
Может будут еще варианты, которые я упустил?
Дмитрий, может вариант сломать систему блок - мультивыноска подойдет? А вариант в Civil: COGO с РД - метка?

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Спасибо! Вариант, как минимум, оригинальный! Но я не сторонник извращений :) Интуиция подсказывает, что это плохой путь.
Как показывает практика, при попытке нестандартного использования объектов, рано или поздно обязательно уткнешься в какое-нибудь серьезное ограничение, которое поставит крест на всей идее.
На мой взгляд, точки COGO хорошо использовать для сосредоточенных одиночных объектов - собственно, для чего они и создавались. В моем же случае, детали взаимодействуют между собой, имеют точки соприкосновения друг с другом, различные динамические параметры для изменения своего вида, динамический параметр для выравнивания деталей относительно друг друга... Точки COGO как минимум не покроют весь доступный функционал блоков.
 

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
ИХМО тут два "стабильных" варианта, в зависимости от задачи и типа оформления, либо выноску поместить непосредственно в блок, либо просто програмно писать в нее "фиксированнный" текст - то есть делать "одноразовую" выноску со значениями на момент создания и не парится с дальнейшей синхронизацией с БД.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Дима_, спасибо за мнение!
В блок - тогда это не выноска уже будет, а атрибут с дополнительными объектами. Придется добавить ряд динамических свойств, чтобы поведение хоть как-то приблизить к поведению выноски. И это нужно будет делать в каждом блоке деталей  :-[ А еще, получится так, что один элемент - одна выноска, а бывает же, что можно одной выноской несколько элементов обозначить. В общем, таким образом мы потеряем кучу возможностей сразу и поимеем редкостную головную боль :(. Но на крайний случай буду иметь в виду этот вариант. Спасибо!
Фиксированный текст без обновления - вообще не вариант. Смысл автоматизации теряется. Одно из основных пожеланий - при добавлении из базы нового типа элемента в чертеж, нужно обновить ведомость и изменить в соответствии с новой нумерацией все выноски. Новая деталь может по иерархии расположиться в середине ведомости, или вообще в самом начале, а нумерация деталей в ней сквозная. Меня не поймут, если я предложу по новой проставлять/перебивать выноски :)

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Тогда могу предложить вариант добавлять "метку" в каждый блок в которую строго будет указывать выноска (если 1 выноска на несколько блоков - то делать их все равно несколько и совмещать их "полки" между собой), а при обновлении "нечаяно освободившиеся" будут "перепривязываться" в заданных допусках к ближайщей точке. То есть "геометрическая" свзяь будет однозначной. Через РД-шку, если чертеж подразумевается править врукопашную, я бы не стал, т.к. такой связи не видно, а сделать могут все-что захочешь.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Чего-то я забыл (а то пишу предыдущий пост и не пойму - где я это уже видел) - у меня-же есть подобное решение в одном проекте на лиспе. Для автоматической простоновки выносок в установленный аттрибут с определенным префиксом (у меня был JOIN_xxx) "видимый в текущей видимости" (у меня были дин. блоки и соответственно разные виды имели подключения в разных точках), где ххх название типа подключения (JOIN_электричество, JOIN_гидравлика и.т.д.), суть лиспа (точнее конкретной его части) - юзер выделят блоки, лисп сканирует на видимые (то есть они НЕ видимые, но лежащие в текущей видимости) на данный момент аттрибуты JOIN_... и группируя их по типам выводит "выборку" (строка запроса - та часть которая ...), после чего анализируя "кучку" параметров создает необходимые выноски (все они приходят в одну точку с единой полкой - просто стрелки от полки могут разбегаться и указывать на "свои" блоки). "Обновление" соответственно работает по точке аттрибута на который указывает выноска.
з.ы. если нужны будут подробности - пиши в личку там распишу, в общий доступ выкладывать не смогу.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ой не... лучше уж тогда атрибут-выноску! :)
Таких меток придется добавлять не одну. Т.к. блоки имеют сложную конфигурацию и в зависимости от свободного места метка может быть с разных сторон. Очень не хочется ограничивать точки привязки выноски - лучше, чтобы проектировщик имел свободу для творчества в этом плане.
Блоки у меня динамические, поэтому метки нужно интегрировать в эту динамику, а потом программно вычислять у каждого вхождения где эта метка находится с учетом состояния динамических параметров.
К тому же, идея такая, что пользователи будут сами создавать блоки для своих деталей, без моего участия...
Как вариант - пойдет, но мне не очень нравится...
Сейчас провожу испытания решений варианта, предложенного Андреем, с учетом замечаний Александра Наумовича. Да, придется попотеть + требовать постоянно загруженного приложения. Но в дальнейшей перспективе, мне видится, что это оправдает себя. По сути, в предложенную Андреем схему достаточно добавить реакции с DeepClone. На первый взгляд - все реализуемо.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
К тому же, идея такая, что пользователи будут сами создавать блоки для своих деталей, без моего участия...
Я как раз-расписывал "спецуху" как создавать такие аттрибуты (и не только их, там мануал на создание блоков на 3 страницы был).
лучше, чтобы проектировщик имел свободу для творчества в этом плане.
ИХМО наоборот "красивей" получается, когда все стрелочки в одинаковое место указывают.
Да, придется попотеть
- как сделаешь - напиши мне тоже интересно...

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Из минусов - если редактировать чертеж неаккуратно, то выноски могут указывать на пустое место
Проверка на пустое место выполняется легко: на основе хэндла пытаешься получить ObjectId (метод называется TryGetObjectId, если мне не изменяет память). если для указанного хэндла не существует соответствующего ObjectId, то это оно и есть - "пустое место".
или вообще на другой объект чертежа, т.к. они никак не связаны с блоком, на который должны указывать.
Чтобы это проверить, в том объекте, на который хранишь ссылку, создай РД в которых запиши, к примеру, GUID. А в РД своей ссылки, помимо ID связанного объекта, дополнительно храни так же значение этого GUID.

Т.о. сначала ищешь объект, ID которого соответствует значению хэндла, хранящегося в РД. Если объект не найден, значит ссылка битая (выполняешь соответствующие исправления). Если найден объект с указанным хэндлом, то на следующем этапе выполняешь проверку соответствия GUID. Ежели проверка прошла, значит объект, скорее всего корректен.


Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Я бы решал так:
1) Создал библиотеку блоков (графических образов объектов) и в РД вставок блоков записывал следующее:
- Хендл объекта выноски.
- Хендл объекта таблицы спецификации.
- № выноски (для восстановления удаленного объекта выноски).
 
2) Сделал алгоритм обновления (генерации) содержимого в табличке спецификации на основе имеющихся вставок блоков на чертеже. В таблицу заносились бы только данные по утвержденному списку имен блоков. Справочник имен блоков хранил бы в соотв. dwg или dwt файле.

3) Анализ возможных действий пользователя:

   a) удаление объекта вставки блока – алгоритм обновления удаляет выноску и обновляет содержимое таблицы.
   b) удаление объекта выноски - алгоритм обновления снова возобновит объект выноски.
   c) удаление таблицы спецификации - алгоритм обновления создает таблицу снова и заполняет ее в соотв. с
       имеющимися объектами на чертеже.
   d) копирование или создание вставки блока -  алгоритм обновления создает выноску (если нужна),
       связывает ее     с    блоком и снова обновляет таблицу и заносит нужные данные в РД вставки блока.
   e) пользователь создает копию таблицы спецификации – алгоритм обновления ни как ни реагирует на эту
       таблицу, т.к. каждый объект вставки блока не хранит в РД Хендл в этой копии таблицы.
   f) копирование или создание выноски – если алгоритм обновления не найдет вставку блока в РД, которого
       есть Хандл этой выноски, то он проигнорирует ее. А если найдет, то связь есть, только вот геометрическое
       положение выноски может быть не таким, каким нужно.
   g) копирование примитивов в другой чертеж -  алгоритм обновления скорее не найдет связи таблицы
       и вставок блоков и сформирует новую таблицу. Выноски лучше вообще удалить и сформировать новые,
       взяв из РД блоков их номера.

Общий смысл работы в том, что есть алгоритм обновления который в текущей ситуации принимает решение и восстанавливает таблицу спецификации или обновляет ее.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
- Хендл объекта выноски.
- Хендл объекта таблицы спецификации.
- № выноски (для восстановления удаленного объекта выноски).
Юзер копирует вхождение блока из одного чертежа в другой, посредством Ctrl + C \ Ctrl + V и весь твой план сразу идёт лесом, ибо обозначенной тобой информации становится явно недостаточно.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
К тому же, идея такая, что пользователи будут сами создавать блоки для своих деталей, без моего участия...
Я как раз-расписывал "спецуху" как создавать такие аттрибуты (и не только их, там мануал на создание блоков на 3 страницы был).
лучше, чтобы проектировщик имел свободу для творчества в этом плане.
ИХМО наоборот "красивей" получается, когда все стрелочки в одинаковое место указывают.
Да, придется попотеть
- как сделаешь - напиши мне тоже интересно...
Вот и я об этом - хочется сделать так, чтобы пользователям потом было легче. Пусть для этого мне придется сейчас больше поработать. Думаю, все должно получиться. Если осилю - поделюсь :)

Цитировать
Цитата: Загорулькин Дмитрий от 03-07-2014, 14:18:35
Из минусов - если редактировать чертеж неаккуратно, то выноски могут указывать на пустое место
Проверка на пустое место выполняется легко: на основе хэндла пытаешься получить ObjectId (метод называется TryGetObjectId, если мне не изменяет память). если для указанного хэндла не существует соответствующего ObjectId, то это оно и есть - "пустое место".
Цитировать
Цитата: Загорулькин Дмитрий от 03-07-2014, 14:18:35
или вообще на другой объект чертежа, т.к. они никак не связаны с блоком, на который должны указывать.
Чтобы это проверить, в том объекте, на который хранишь ссылку, создай РД в которых запиши, к примеру, GUID. А в РД своей ссылки, помимо ID связанного объекта, дополнительно храни так же значение этого GUID.
Т.о. сначала ищешь объект, ID которого соответствует значению хэндла, хранящегося в РД. Если объект не найден, значит ссылка битая (выполняешь соответствующие исправления). Если найден объект с указанным хэндлом, то на следующем этапе выполняешь проверку соответствия GUID. Ежели проверка прошла, значит объект, скорее всего корректен.
Я имел в виду геометрическое указание, как на картинке. После сдвига деталей, одна выноска указывает не на ту деталь, вторая - в пустое место. И в том варианте, в котором я озвучивал этот минус, никак не "отловить" такие невзаимные изменения.


Я бы решал так:
1) Создал библиотеку блоков (графических образов объектов) и в РД вставок блоков записывал следующее:
- Хендл объекта выноски.
- Хендл объекта таблицы спецификации.
- № выноски (для восстановления удаленного объекта выноски).
 
2) Сделал алгоритм обновления (генерации) содержимого в табличке спецификации на основе имеющихся вставок блоков на чертеже. В таблицу заносились бы только данные по утвержденному списку имен блоков. Справочник имен блоков хранил бы в соотв. dwg или dwt файле.

3) Анализ возможных действий пользователя:

   a) удаление объекта вставки блока – алгоритм обновления удаляет выноску и обновляет содержимое таблицы.
   b) удаление объекта выноски - алгоритм обновления снова возобновит объект выноски.
   c) удаление таблицы спецификации - алгоритм обновления создает таблицу снова и заполняет ее в соотв. с
       имеющимися объектами на чертеже.
   d) копирование или создание вставки блока -  алгоритм обновления создает выноску (если нужна),
       связывает ее     с    блоком и снова обновляет таблицу и заносит нужные данные в РД вставки блока.
   e) пользователь создает копию таблицы спецификации – алгоритм обновления ни как ни реагирует на эту
       таблицу, т.к. каждый объект вставки блока не хранит в РД Хендл в этой копии таблицы.
   f) копирование или создание выноски – если алгоритм обновления не найдет вставку блока в РД, которого
       есть Хандл этой выноски, то он проигнорирует ее. А если найдет, то связь есть, только вот геометрическое
       положение выноски может быть не таким, каким нужно.
   g) копирование примитивов в другой чертеж -  алгоритм обновления скорее не найдет связи таблицы
       и вставок блоков и сформирует новую таблицу. Выноски лучше вообще удалить и сформировать новые,
       взяв из РД блоков их номера.

Общий смысл работы в том, что есть алгоритм обновления который в текущей ситуации принимает решение и восстанавливает таблицу спецификации или обновляет ее.

Это уже другой вопрос - каким образом обрабатывать изменения объектов. В зависимости от задачи, могут быть совершенно разные действия.
Вопрос же стоит в том, чтобы связать два объекта между собой ссылками друг на друга и обеспечить сохранение/модификацию этой связи при создании, копировании и удалении объектов. А уже потом, поняв что объект меняется, решать что делать со  связанными объектами. Думаю, что можно сделать универсальный инструмент, который потом можно будет использовать не только для выносок и деталей, но и для любых других объектов чертежа, которые нужно будет связать.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Я имел в виду геометрическое указание, как на картинке. После сдвига деталей, одна выноска указывает не на ту деталь, вторая - в пустое место. И в том варианте, в котором я озвучивал этот минус, никак не "отловить" такие невзаимные изменения.
Тогда, как вариант к размышлению:
1. При открытии чертежа производишь анализ РД объектов, извлекая информацию о связях.

2. Для каждого из объектов, участвующего в назначенных связях, получаешь геометрические границы (прямоугольные) и запоминаешь смещения, а так же диагональ прямоугольника.

3. Вычисляешь смещение центра геометрической границы своей выноски относительно центра геометрической границы объекта, на который она указывает. Все обозначенные извлечённые данные сохраняешь во временную базу данных (не Database). По мере изменений в чертеже, корректируешь содержимое этой базы (она живёт в памяти).

4. В обработчике события отслеживаешь перемещение объекта, на который указывает ссылка, синхронизируя перемещение ссылки (новое положение выноски расчитываешь относительно ранее вычисленного и сохранённого в записи базы смещения, а так же диагонали. Значение диагонали позволяет отследить факт масштабирования объекта и в соответствии с этим скорректировать расчёт.

5. При закрытии чертежа, информацию из базы данных записываешь в РД объектов, а саму базу - в утиль.

Думаю, что для перемещений и масштабирования это сработает. Но вот в случае поворота... В этом случае геометрические границы не поворачиваются, но вместо этого изменяют свои размеры. Поворот придётся обрабатывать как-то по иному...

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Юзер копирует вхождение блока из одного чертежа в другой, посредством Ctrl + C \ Ctrl + V и весь твой план сразу идёт лесом, ибо обозначенной тобой информации становится явно недостаточно.

Так я же и говорю, что через буфер обмена будут проблемы и программа генерации таблички все сделает по
новому, т.е. по вставкам блоков сформирует новую таблицу. Выноски летят к чертям и копируемая таблица тоже не актуальна. Так что перенос проекта через буфер обмена не возможет. Для переноса данных в другой чертеж просто написать алгоритм экспорта данных проекта в другой чертеж. Это не сложно.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Действительно, все получилось сделать:
- создать связи
- сохранить связи в чертеже
- восстановить и актуализировать информацию при открытии чертежа
- отловить событие копирования связанных объектов внутри чертежа и добавить связь копиям
- отловить событие модификации связанных объектов и сгенерировать события для того, чтобы приложение, пользующееся функционалом связей, могло каким-то образом на это отреагировать

Но вот через буфер обмена никак не получается пробиться. Загвоздка в том, что такое копирование как-то хитро работает. Как показывают опыты, при этом создается в папке Temp временный чертеж (частичная копия исходного чертежа?), из которой уже объекты переносятся в чертеж назначения. Какие я только события не пробовал (Database.BeginDeepClone, Database.BeginDeepCloneTranslation, Database.BeginWblockEntireDatabase, Database.BeginWblockObjects, Database.BeginWblockSelectedObjects, Database.BeginDxfOut, Database.WblockMappingAvailable, Database.WblockNotice, Database.BeginWblockBlock) - создание временного чертежа никак не отлавливается.
При Ctrl+C возникает только событие WblockNotice, которое имеет в аргументах ссылку на базу данных исходного чертежа (непонятно зачем, ведь аргумент sender - это та же самая база данных).
При Ctrl+V в другом чертеже, срабатывают уже события базы данных того чертежа, в который вставляем - BeginDeepClone и BeginDeepCloneTranslation. В их аргументах OriginalDatabase - БД временного файла из Temp, DestinationDatabase - база данных чертежа, в который копируем. При этом, в NOD базы данных временного файла нет данных о ссылках, хотя в базе данных исходного чертежа в NOD эти данные есть.

Поэтому, теперь меня волнуют два вопроса:
- Все ли правильно с событием WblockNotice? Может быть, в аргументах там должна фигурировать еще и вторая база данных?
- Может быть, есть какое-то еще событие базы данных/документа/приложения/системы, чтобы можно было отловить копирование объектов через буфер обмена?

Буду благодарен, если кто-нибудь поможет с этим!

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
- Может быть, есть какое-то еще событие базы данных/документа/приложения/системы, чтобы можно было отловить копирование объектов через буфер обмена?

Если нужно обратиться к добавляемому в документ примитиву,
то можно обработать событие добавления примитива в документ.
Когда через буфер обмена в документ вставляются примитивы, то это событие наступает.
В .NET пока не искал, но на ActiveX есть такое событие у документа
Вот код такой:

Код - vb.net [Выбрать]
  1.  
  2.         Private WithEvents myDoc As Autodesk.AutoCAD.Interop.AcadDocument
  3.         Private Sub myDoc_ObjectAdded(ByVal Obj As Object) Handles myDoc.ObjectAdded
  4.             Try
  5.                 Dim COM_Ent As Autodesk.AutoCAD.Interop.Common.AcadEntity = _
  6.                     DirectCast(Obj, Autodesk.AutoCAD.Interop.Common.AcadEntity)
  7.                 Dim HWND_ENT As String = COM_Ent.Handle
  8.                 ' по HWND_ENT из DataBase можно получить объект Autodesk.AutoCAD.DatabaseServices.Entity
  9.             Catch ex As Exception
  10.             End Try
  11.         End Sub
  12.  


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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Действительно, все получилось сделать:- создать связи- сохранить связи в чертеже- восстановить и актуализировать информацию при открытии чертежа- отловить событие копирования связанных объектов внутри чертежа и добавить связь копиям- отловить событие модификации связанных объектов и сгенерировать события для того, чтобы приложение, пользующееся функционалом связей, могло каким-то образом на это отреагировать
А ежели Database отредактируют на машине, на которой нет твоего плагина?

Цитировать
Но вот через буфер обмена никак не получается пробиться. Загвоздка в том, что такое копирование как-то хитро работает.
В составе IdMapping хранится информация о том, какому идентификатору нового объекта соответствует какой идентификатор копируемого из др. чертежа объекта. Имея на руках эту инфу, ты можешь и расширенные данные подтянуть соответствующим образом и не важно сколько там промежуточных временных файлов создаётся за кулисами (если я верно понял твой вопрос).

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Если "нормально" совсем никак, то вариант - попробывать использовать грубый вариант - Document.CommandWillStart - смотреть соответствующие команды работы с буфером обмена и варианты завершения Document.Command... c дальнейшим анализом Clipboard.GetData(...).

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Если нужно обратиться к добавляемому в документ примитиву,
то можно обработать событие добавления примитива в документ.
С этим проблем нет, какие примитивы добавляются в базу я вижу через IdMapping.
В составе IdMapping хранится информация о том, какому идентификатору нового объекта соответствует какой идентификатор копируемого из др. чертежа объекта. Имея на руках эту инфу, ты можешь и расширенные данные подтянуть соответствующим образом и не важно сколько там промежуточных временных файлов создаётся за кулисами (если я верно понял твой вопрос).
Думаешь, в промежуточных Database ID и/или хендлы объектов не меняются? Мысль интересная, спасибо! Надо проверить. Завтра первым делом займусь этим :) Кстати, расширенные данные я не использую совсем. За основу взял твою идею "менеджера связей", между сеансами сохраняю его в NOD базы чертежа.
Если "нормально" совсем никак, то вариант - попробывать использовать грубый вариант - Document.CommandWillStart - смотреть соответствующие команды работы с буфером обмена и варианты завершения Command(...) c дальнейшим анализом Clipboard.GetData(...).
Тоже дельная мысль, спасибо!

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Если "нормально" совсем никак, то вариант - попробывать использовать грубый вариант - Document.CommandWillStart
Кстати, именно этот вариант я несколько лет назад использовал, когда нужно было отслеживать копирование пользователем таблиц из Excel и вставку их в AutoCAD: отлавливал запуск команды вставки из буфера (сейчас точного имени не помню, но ты и сам можешь легко это выяснить) и анализировал содержимое буфера обмена. Если там находился OLE объект от Excel'я, то выполнял преобразование контента в соответствующим образом отформатированную таблицу AutoCAD, которую затем вставлял в указанное юзером место (висела на курсоре, ожидая вставки). Так что способ отслеживания Ctrl + V посредством мониторинга Document.CommandWillStart работает на 100%.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
1. Команд копирования в буфер (насколько я помню) две: COPYCLIP и COPYBASE, а вставки три: PASTECLIP, PASTEORIG, PASTEBLOCK
2. Воспользуйся утилитой ARXDBG (из состава ObjectARX SDK, готовые arx-файлы можно скачать у меня: http://www.maestrogroup.com.ua/support/ ) для того, чтобы понять какие события возникают при операциях копирования в буфер и вставки из буфера. В контекстном меню выберешь команду REACTORS и включишь все флажки. Желательно сразу включить запись лога в файл, так как будет очень много сообщений. Проблемой может быть то, что не все реакторы, которые есть в ObjectARX реализованы в виде событий в AutoCAD .NET API.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
- Все ли правильно с событием WblockNotice? Может быть, в аргументах там должна фигурировать еще и вторая база данных?
Всё правильно, но ты сравниваешь не те базы. Нужно сравнивать e.To и HostApplicationServices.WorkingDatabase
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Думаешь, в промежуточных Database ID и/или хендлы объектов не меняются?
Меняются конечно, но через IdMapping ты как раз можешь отследить что было и что стало. И более то ты можешь в нужный момент в IdMapping подсунуть NOD, чтобы и она скопировалась, если в этом есть необходимость.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Спасибо! Сейчас, с новыми силами и вооружившись вашими советами, попробую одолеть эту задачу :)

Александр Наумович, низкий Вам поклон! Запустил утилиту регистрации событий, получил такой листинг:
[Doc Event] : Command will Start        : COPYBASE
Базовая точка:
[Editor Event] : Prompting For Point
[Editor Event] : Point Filter
[Editor Event] : Point Monitor
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Point Filter
[Editor Event] : Point Monitor
[Editor Event] : Point Filter
[Editor Event] : Point Monitor
[Editor Event] : Point Filter
[Editor Event] : Point Monitor
[Editor Event] : Prompted For Point
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added      найдено: 5

[Editor Event] : Prompting For Selection
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Doc Event] : Implied Selection Changed
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[DB Event : 749142272] : Object Modified           : <DrawOrderTable, 27F0>
[DB Event : 749142272] : Object Modified           : <DrawOrderTable, 27F0>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 5D>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 119C>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 11A4>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9B16>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9B3B>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9B60>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9B86>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9BAC>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 9BD3>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, AF81>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 11759>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 11778>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 117AF>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 11B71>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13A73>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13A8C>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13ABC>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13AD9>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13B08>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13B50>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13B6B>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13B92>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13BAD>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13BC8>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13BE2>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13BF8>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13C11>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13C62>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 13C7E>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 14584>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 146A7>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 146AC>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 146B1>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 146B7>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 148AC>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 155AD>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 15E59>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 17792>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F05A>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F085>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F4B7>
[DB Event : 749142272] : Object Modified           : <BlockTableRecord, 1F8E2>
[DB Event : 749142272] : Wblock Notice             : To = C:\Users\Zagorulkin_DY\appdata\local\autodesk\c3d 2014\rus\template\_autocad civil 3d (metric)_rus.dwt
[DB Event : 55343840] : Database Constructed
[Editor Event] : Selection Added
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Editor Event] : Prompting For Selection
[Editor Event] : Selection Added
[Editor Event] : Prompt For Selection Ending
[Editor Event] : Prompted For Selection
[Doc Event] : Implied Selection Changed
[Doc Event] : Command Ended             : COPYBASE
Ключевой для меня момент - [DB Event : 55343840] : Database Constructed, т.е., создание базы данных отловить можно! Просто для этого нужно использовать события не отдельного объекта Database, а класса Database!
Дальше, думаю, проблем быть не должно.
В общем, копирование объектов между чертежами выполняется примерно по такому сценарию (может кому пригодится):
- при Ctrl+C создается новая база данных чертежа, в нее помещаются выбранные объекты
- далее, эта база данных сохраняется в чертеж в папке Temp с именем типа "A$C70F66046.DWG", на каждое копирование создается новый чертеж
- каким-то образом приложение отслеживает связь между чертежом, из которого копировали и этими временными файлами, т.к. после закрытия чертежа все относящиеся к нему временные файлы удаляются из Temp
- в буфере обмена также есть копия этого чертежа, потому что даже после закрытия файла-источника (соответственно, уничтожения всех его временных файлов), можно выполнить вставку ранее скопированных объектов в другой чертеж (если мне память не изменяет)
- соответственно, при вставке этот временный файл вставляется как блок в чертеж и в зависимости от команды вставки расчленяется или нет. Если нет (pasteblock) - то получается блок с именем, которое было у файла.

Кстати, по поводу события WblockNotice вопрос остается открытым :)
« Последнее редактирование: 11-07-2014, 11:13:56 от Загорулькин Дмитрий »

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я вижу, что ты воспользовался не ARXDBG, а MGDDBG. И похоже я прав, что далеко не все реакторы ObjectARX имеют эквиваленты в AutoCAD .NET API, а некоторые еще и неправильно работают. В частности WblockNotice. В ObjectARX в такой же ситуации:
[EVENT REACTOR] : [Wblock Notice]   (Db = 000000002A4443E0  "C:\Temp\Drawing1_1_1_1438.sv$")
[EVENT REACTOR] : [Begin Deep Clone: context = Wblock]   (Db = 0000000030E60EF0  "")
Соотвественно текущая база и та, в которую выполняется Wblock - разные.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я вижу, что ты воспользовался не ARXDBG, а MGDDBG. И похоже я прав, что далеко не все реакторы ObjectARX имеют эквиваленты в AutoCAD .NET API, а некоторые еще и неправильно работают. В частности WblockNotice. В ObjectARX в такой же ситуации:
[EVENT REACTOR] : [Wblock Notice]   (Db = 000000002A4443E0  "C:\Temp\Drawing1_1_1_1438.sv$")
[EVENT REACTOR] : [Begin Deep Clone: context = Wblock]   (Db = 0000000030E60EF0  "")
Соотвественно текущая база и так, в которую выполняется Wblock - разные.
Да, у меня MGDDBG уже была на компьютере, решил ей воспользоваться. Думал, что большой разницы между ними нет...
Вот такое поведение, как в ObjectARX я от этого реактора и ожидал...
А что это за идентификатор базы? Db = 0000000030E60EF0

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
а некоторые еще и неправильно работают...
Соотвественно текущая база и так, в которую выполняется Wblock - разные.
А почему это ошибка (я просто спрашиваю, а не говорю что все правильно), или если так правильней в чем именно ошибка - копипаста-то работает (а как им там внутри это реализовывать это ихмо их дело).

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Попробую объяснить.
Есть база чертежа (База1). Отслеживаем у нее событие WblockNotice (из мурзилки: Wraps AcRxEventReactor::wblockNotice. The event indicates that a wblock operation is about to start.) - это предупреждение о том, что вот-вот начнется копирование объектов в другую базу (База2).
У делегата этого события есть два аргумента, первый - object sender. В нашем случае - это База1, она сообщает о событии.
Второй аргумент - WblockNoticeEventArgs e. У него только одно отличие от системного EventArgs - свойство "To". переводим на русский язык - это предлог "В". Логично предположить, что это какая-то характеристика объекта, в который будет производиться копия. Смотрим мурзилку: Gets the database being written to.
По идее, получается, что в sender должна быть База1, в e.To - База2.
По факту, при выполнении кода, я обнаружил, что в sender и в e.To - одна и та же база данных - База1.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Все - да, то что свойство TO  показывет свою-же, а не "целевую" базу это явно косяк, просто я из объяснения Александра, не понял, что речь идет о разнице между arx/net...
я подумал, что то что базы разные и есть ошибка - и удивился почему...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
А что это за идентификатор базы?
Я посмотрел в коде ARXDBG - это просто адрес в памяти, где расположен это объект.
А почему это ошибка (я просто спрашиваю, а не говорю что все правильно), или если так правильней в чем именно ошибка - копипаста-то работает (а как им там внутри это реализовывать это ихмо их дело).
Дима. В ObjectARX есть два реактора:
AcRxEventReactor::wblockNotice и AcEditorReactor::wblockNotice и в документации сказано, что для первого реактора эта база в которую будут копироваться объекты в результате Wblock, а для второго реактора - база откуда они будут копироваться. По факту (судя по моему протоколу ARXDBG) это одна и таже новая временная база:
[EVENT REACTOR] : [Wblock Notice]   (Db = 000000002A4443E0  "C:\Temp\Drawing1_1_1_1438.sv$")
[ED REACTOR]    : [Wblock Notice]   (Db = 000000002A4443E0  "C:\Temp\Drawing1_1_1_1438.sv$")
Database.WblockNotice должно быть "оберткой" для AcRxEventReactor::wblockNotice (исходя тоже из документации) и соотвественно должна возвращать базу в которую будет выполняться Wblone. Но похоже это не так.


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

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Да спасибо - я уже разобрался (не так понял, что Вы имеете в виду под ошибкой).

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я посмотрел в коде ARXDBG - это просто адрес в памяти, где расположен это объект.
Эх, жаль. Я думал, что это какой-то уникальный идентификатор базы данных. Пока я такого не смог найти. Может быть, Вы подскажете? :)
Но похоже это не так.
Можете сами проверить. Возможно и АДН это интересно будет :)
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. using Autodesk.AutoCAD.ApplicationServices;
  7. using Autodesk.AutoCAD.DatabaseServices;
  8. using Autodesk.AutoCAD.EditorInput;
  9. using Autodesk.AutoCAD.Runtime;
  10.  
  11. namespace WblockNoticeTest
  12. {
  13.     public class CmdClass
  14.     {
  15.         Document adoc = Application.DocumentManager.MdiActiveDocument;
  16.         Database db = Application.DocumentManager.MdiActiveDocument.Database;
  17.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  18.  
  19.         [CommandMethod("WblockNoticeTest")]
  20.         public void AddEventHandler()
  21.         {
  22.             db.WblockNotice += new WblockNoticeEventHandler(db_WblockNotice);
  23.             ed.WriteMessage("\nSelect objects and run command COPYCLIP or COBYBASE");
  24.         }
  25.  
  26.         void db_WblockNotice(object sender, WblockNoticeEventArgs e)
  27.         {
  28.             Database sendDb = sender as Database, toDb = e.To;
  29.             Application.ShowAlertDialog(sendDb.Equals(toDb) ? "Databases are equivalent!" : "Databases differ!");
  30.         }
  31.     }
  32. }

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Я посмотрел в коде ARXDBG - это просто адрес в памяти, где расположен это объект.
Эх, жаль. Я думал, что это какой-то уникальный идентификатор базы данных.
Ну, с некоторыми ограничениями, это в общем-то так.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
А из NET к нему можно добраться?

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
К адресу или объекту?

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ок, задам вопрос по-другому :)
У меня в одной переменной сохранена одна БД, в другой - другая. По какому свойству я могу определить, что они разные? Не применяя метода Equal.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
По какому свойству я могу определить, что они разные?
Оххх... По поводу сравнения объектов это тема реально на целую книгу. Что есть "одинаковые БД", equal как-раз таки и проверяет ссылаются ли объекты на один и тот-же физический адрес (то есть, что это одно и то-же). А вот если дважды открыть один и тот-же файл можно-ли это рассматривать как "одиноковые" БД - вопрос не однозначен (по крайней мере время открытия будет разным, handle внутренних объектов то-же и пр.), то есть надо определиться, что все-таки важно в сравнении - быть может, например, достаточно будет сверить свойства Filename...

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Не-не-не, мне именно это и надо - что объект один и тот же. В принципе, equal устраивает. Просто сейчас разбираюсь с копированием через буфер, там баз временных создается параллельно не одна штука (при переключении активного чертежа зачем-то создаются и практически сразу же уничтожаются 3 базы чертежа  :o). Хотелось бы понимать какая база в текущий момент вызвала событие.
А FileName - вообще не показатель. У нового чертежа там хранится адрес файла шаблона, у сохраненного - сохраненный путь, у базы данных без чертежа - пустая строка. А интересуют именно "бесчертежные" базы данных...

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Все я уже не ухватываю - зачем тебе базу сравнивать - каую ты базу хочешь отловить?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
А из NET к нему можно добраться?
Да. Database.UnmanagedObject
У меня в одной переменной сохранена одна БД, в другой - другая.
Только по полному пути доступу к файлу, если они сохранены. А если они не сохранены, то непонятны критерии сравнения на эквивалентность.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Какая-то новая беда.
Разобрался с копированием объектов из чертежа во временный чертеж в папке Temp. В этом процессе все логично и понятно.
Анализирую IdMapping, были у объектов одни хендлы, стали другие. Открываю этот временный чертеж - да, там именно те хендлы у объектов, которые показал IdMapping. Связь между объектами записана в словарь и является актуальной.
Выполняю вставку скопированного в другой чертеж - IdMapping показывает уже совершенно другие хендлы! Причем, хендлы из оригинальной базы совпадают с хендлами в базе назначения! Соответственно, связь, записанная в словарях, не распознается :( Что это такое? Снова баг или я что-то не учитываю?
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.ApplicationServices;
  7. using Autodesk.AutoCAD.Runtime;
  8. using Autodesk.AutoCAD.EditorInput;
  9.  
  10. namespace PasteTest
  11. {
  12.     public class CmdClass
  13.     {
  14.         Document adoc = Application.DocumentManager.MdiActiveDocument;
  15.         Database db = Application.DocumentManager.MdiActiveDocument.Database;
  16.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  17.  
  18.         [CommandMethod("PasteTest")]
  19.         public void AddPasteHandler()
  20.         {
  21.             db.BeginDeepCloneTranslation += new IdMappingEventHandler(db_BeginDeepCloneTranslation);          
  22.             db.InsertMappingAvailable += new IdMappingEventHandler(db_InsertMappingAvailable);
  23.             Database.DatabaseConstructed += new EventHandler(Database_DatabaseConstructed);
  24.             ed.WriteMessage("\nRun command PASTECLIP, PASTEBASE or PASTEBLOCK");
  25.         }
  26.  
  27.         void db_InsertMappingAvailable(object sender, IdMappingEventArgs e)
  28.         {
  29.             IdMappingSearch(e.IdMapping);
  30.         }      
  31.  
  32.         void Database_DatabaseConstructed(object sender, EventArgs e)
  33.         {
  34.             (sender as Database).BeginDeepCloneTranslation += new IdMappingEventHandler(CmdClass_BeginDeepCloneTranslation);
  35.         }
  36.  
  37.         void CmdClass_BeginDeepCloneTranslation(object sender, IdMappingEventArgs e)
  38.         {
  39.             IdMappingSearch(e.IdMapping);
  40.         }
  41.  
  42.         void db_BeginDeepCloneTranslation(object sender, IdMappingEventArgs e)
  43.         {
  44.             IdMappingSearch(e.IdMapping);
  45.         }
  46.  
  47.         void IdMappingSearch(IdMapping idMapping)
  48.         {
  49.             ed.WriteMessage("\nDeepCloneContext: " + idMapping.DeepCloneContext);
  50.             ed.WriteMessage("\nOriginalDatabase: " + idMapping.OriginalDatabase.UnmanagedObject.ToInt64() + " FileName: " + idMapping.OriginalDatabase.Filename);
  51.             ed.WriteMessage("\nDestinationDatabase: " + idMapping.DestinationDatabase.UnmanagedObject.ToInt64() + " FileName: " + idMapping.DestinationDatabase.Filename);
  52.             List<IdPair> idPairList = idMapping.Cast<IdPair>().Where(item => item.IsCloned).ToList();
  53.             ed.WriteMessage("\nIdPairs:");
  54.             foreach (IdPair idPair in idPairList)
  55.             {
  56.                 ed.WriteMessage("\nObjectType: {4}, KeyId: {0}, ValueId: {1}, KeyHandle: {2}, ValueHandle: {3}", idPair.Key, idPair.Value, idPair.Key.Handle, idPair.Value.Handle, idPair.Key.ObjectClass.Name);
  57.             }
  58.             ed.WriteMessage("\n");
  59.         }
  60.     }
  61. }
  62.  

Команда: _pasteclip Повторное определение блока _Oblique  пропущено.
DeepCloneContext: Insert
OriginalDatabase: 1221104048 FileName: C:\Users\ZAGORU~1\AppData\Local\Temp\A$C7CEB7907.DWG
DestinationDatabase: 766323488 FileName: C:\Users\Zagorulkin_DY\appdata\local\autodesk\c3d 2014\rus\template\_autocad civil 3d (metric)_rus.dwt
IdPairs:
ObjectType: AcDbLine, KeyId: (8796086484512), ValueId: (8796086071728), KeyHandle: 2019B, ValueHandle: 2019B              <------------------------------- !!! Хендлы одинаковые
ObjectType: AcDbCircle, KeyId: (8796086484528), ValueId: (8796086071744), KeyHandle: 2019C, ValueHandle: 2019C           <------------------------------- !!! Хендлы одинаковые
DeepCloneContext: Insert
OriginalDatabase: 1221104048 FileName: C:\Users\ZAGORU~1\AppData\Local\Temp\A$C7CEB7907.DWG
DestinationDatabase: 766323488 FileName: C:\Users\Zagorulkin_DY\appdata\local\autodesk\c3d 2014\rus\template\_autocad civil 3d (metric)_rus.dwt
IdPairs:
ObjectType: AcDbLine, KeyId: (8796086484512), ValueId: (8796086071728), KeyHandle: 2019B, ValueHandle: 2019B              <------------------------------- !!! Хендлы одинаковые
ObjectType: AcDbCircle, KeyId: (8796086484528), ValueId: (8796086071744), KeyHandle: 2019C, ValueHandle: 2019C           <------------------------------- !!! Хендлы одинаковые
Точка вставки:
DeepCloneContext: Explode
OriginalDatabase: 766323488 FileName: C:\Users\Zagorulkin_DY\appdata\local\autodesk\c3d 2014\rus\template\_autocad civil 3d (metric)_rus.dwt
DestinationDatabase: 766323488 FileName: C:\Users\Zagorulkin_DY\appdata\local\autodesk\c3d 2014\rus\template\_autocad civil 3d (metric)_rus.dwt
IdPairs:
ObjectType: AcDbLine, KeyId: (8796086071728), ValueId: (8796086071840), KeyHandle: 2019B, ValueHandle: 201A2
ObjectType: AcDbCircle, KeyId: (8796086071744), ValueId: (8796086071856), KeyHandle: 2019C, ValueHandle: 201A3

https://screencast.autodesk.com/main/details/a1be4073-e6f4-448a-853c-023bb3659707
« Последнее редактирование: 14-07-2014, 16:14:07 от Загорулькин Дмитрий »

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Разобрался с копированием объектов из чертежа во временный чертеж в папке Temp.В этом процессе все логично и понятно.
IdMapping показывает уже совершенно другие хендлы!
Вся беда в том, что примитивы при вставке берутся не из файла в папке temp - проверить просто - сотри их - вставка продолжит работать - хотя может как кэш он и используется - надо "рыть" - смотреть, что еще есть в Clipboard.GetDataObject().GetFormats() и где-то там, что-то явно лежит, на основе чего база и создается (и дай бог чтоб, это был какой-нибудь поток в памяти с "честным" файлом, а если это не так - то может и придется координально менять тактику).
з.ы. предпалагаю, что на этапе копирования, вначали wblo'чаться выбранные элементы, а потом из них создается и сам "буфер обмена" с которым уже непосредственно работает автокад.


Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Возможно и так, но это не объясняет, почему в разных базах данных объекты имеют одинаковые хендлы. Пускай копируется не из файла а из буфера обмена - события же все равно срабатывают. Базы данных различные - это тоже легко проверяется. Почему же одинаковые хендлы? Наверное, при реализации обертки над ARX, из одной переменной оба значения взяли. Другого объяснения я не вижу :(
Я, конечно, поковыряю буфер обмена. Сдается мне, что там я найду копию файла из Temp...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Возможно и так, но это не объясняет, почему в разных базах данных объекты имеют одинаковые хендлы.
А что в этом не так? Могут иметь - не вижу в этом противоречия.
P.S.: Кстати зря в ролике во втором файле отключил реакторы из ARXDBG.  Вполне допускаю, что они бы что-то подсказали.
P.S.S.: А вообще-то в чем ты видишь проблему я совсем не понял. В твоём протоколе дважды DeepCloneContext: Insert с одними и теми же метками примитивов? Но это мне понятно. Сначала вставляется внешний файл как блок и таскается за курсором, а когда точка указана тут происходит повторная вставка в указанную точку. Ну и последний этап - расчленение вставленного блока (). Интересно, что если в момент когда запрашивается точка вставки нажать ESC, то вставленный блок (BlockTableRecord с именем типа "A$XXXXXXX") не удаляется и остается в чертеже, но вставки блока (BlockReference) с таким именем не возникает. Если же команда завершается штатно, то блока нет (он удаляется).
« Последнее редактирование: 15-07-2014, 01:53:00 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Моя проблема в том, что:
1) я использую хендлы примитивов для хранения связи между ними
2) в процессе вставки хендлы вставляемых объектов не соответствуют вообще ничему и откуда берутся непонятно :(

При копировании IdMapping четко и однозначно показывает - был такой объект (ID такой-то, хендл такой-то), стал другой объект (ID другой, и хендл другой). Я имею возможность отследить изменение хендлов и актуализировать данные о связях.
При вставке реакции срабатывают, IdMapping выдается, но там в парах хендлы объектов исходной и целевой базы одинаковые (хотя ID - разные, базы - разные) и откуда взявшиеся - неизвестно.

Как я понимаю, дважды DeepCloneContext: Insert потому, что срабатывают две реакции параллельно на одно и то же событие клонирования объектов в базу: InsertMappingAvailable и BeginDeepCloneTranslation. Потом уже, при указании точки, никакого "клонирования" из других БД не происходит, поэтому эти реакции не срабатывают, там будут уже ObjectAppended, ObjectModified и т.п.

ARXDBG я пробовал не отключать. К сожалению, утилита, при клонировании объектов между БД, показывает только хендлы объектов для целевой базы.

P.S. Александр Наумович, очень прошу Вас (если, конечно, возможности/время позволяет) проверить, что выдаст при вставке ARXовский аналог IdMapping! Я, конечно, могу оказаться неправ, но пока я склоняюсь к тому, что проблема именно из-за неправильной реализации.
« Последнее редактирование: 15-07-2014, 11:11:11 от Загорулькин Дмитрий »

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
P.S. Александр Наумович, очень прошу Вас (если, конечно, возможности/время позволяет) проверить, что выдаст при вставке ARXовский аналог IdMapping! Я, конечно, могу оказаться неправ, но пока я склоняюсь к тому, что проблема именно из-за неправильной реализации.
Боюсь что проблема вот в следующем. В момент возникновения события BeginDeepCloneTranslation IdMapping еще неправильный (необработанный) о чем говорится в документации. Правильным IdMapping становится в момент события AcEditorReactor::endDeepClone, эквивалент которого в .NET API Database.DeepCloneEnded. Но тут то и возникает проблема, т.к. у Database.DeepCloneEnded нет параметра, в котором был бы IdMapping, а у AcEditorReactor::endDeepClone он есть. Так что как получить правильный  IdMapping в AutoCAD .NET API я сейчас даже и не соображу...

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Стоп... Что-то у меня совсем ум за разум заходит... В IdMapping нет Handle. Там только пары Id и ссылки на базы. Id разные, базы разные - тут порядок. А хендлы я уже из Id получаю, может тут какой подвох?  :-\

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

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

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Подвох в том, что в тот момент когда ты их получаешь они еще не вычислены,
Кто не вычесленны id или handle - если handle - тогда все просто - сохранить IdMapping на момент вызова BeginDeepCloneTranslation, а получить handle по событию DeepCloneEnded - но ИХМО тут загвоздка еще в чем-то (то есть такой вариант скорее всего вернет все тоже-самое). Я думаю, что где-то в этой цеопчке создаются все-же невидимая для событий база - ту в которую копируют и соответственно "цепочка" преобразований - с пропуском.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Кто не вычесленны id или handle - если handle - тогда все просто - сохранить на момент вызова BeginDeepCloneTranslation, а получить handle по событию DeepCloneEnded
Думаю что именно так и нужно сделать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Попробовал сохранить объект IdMapping в событии BeginDeepCloneTranslation и прочитать его в событии DeepCloneEnded - объект IdMapping между этими событиями не изменился (хотя, особой надежды не было), хендлы тоже другими не стали.
Попробовал установить рабочей базу данных, из которой выполняем копирование, с помощью транзакции вытащить из нее объект и посмотреть его хендл - тот же самый, что и из Id. Это, в моем понимании, противоречит тому, что IdMapping некорректный, раз в исходной БД объект с тем же хендлом.

Посмотрел цепочку событий при вставке, порядок такой:
- создается пустая база данных (исходная БД)
- в нее читаются данные из временного ДВГ файла
- выполняется вставка блока в чертеж (БД назначения)
- запрашивается точка вставки
- исходная БД уничтожается
- взрывается блок

Провел опыт с закрытым исходным чертежом:
Временный файл создается по данным из буфера обмена, после вставки он удаляется. Еще раз вставляем - снова создается временный файл уже с другим случайным именем и опять после вставки он удаляется. После примерно пяти вставок, я его перехватил до удаления, переименовал и открыл - там мои объекты все еще с "актуальными" хендлами.

Попробовал сохранить исходную БД в другом файле - AutoCAD падает без каких-либо сообщений... Тупик :(

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Дмитрий проверь вот-что (если конечно мой вариант в который я сам не верю, но Александр допускает - таки сработает) - если отслеживать по ObjectID не будет-ли видно "цепочки" при первом копировании->вставки (то есть, не будут-ли прослеживаться последовательные изменения objectid от копируемого до вставляемого), но я практически уверен, что при повторной вставке того-же объекта, в том месте где одинаковый handle переходит сам в себя, из "ниоткуда" появиться "перворожденный" ObjectID.
з.ы. опс - да вижу что простой вариант не сработал.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Попробовал сохранить объект IdMapping в событии BeginDeepClone и прочитать его в событии EndDeepClone - объект IdMapping между этими событиями не изменился (хотя, особой надежды не было)
Объект IdMapping сохранять смысла я не вижу. Наверное нужно сохранять Id'сы для всех пар, а в EndDeepClone получать для них Handle'ы
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ок, попробую сохранять Ids...
А когда у нас идет наполнение БД из файла без его открытия (например, методом ReadDwgFile) хендлы объектов чертежа сохраняются?

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Наверное нужно сохранять Id'сы для всех пар
Вот тут я точно не вижу смысла. Могут измениться объекты - но id сами по себе точно не "испортяться" - другое дело, что они могут потерять актуальность (то есть на момент завершения они уже станут  другими - но это нам все равно никак не поможет).

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
А когда у нас идет наполнение БД из файла без его открытия (например, методом ReadDwgFile) хендлы объектов чертежа сохраняются?
Конечно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Сохранение Id тоже не дало результата...
Может быть, при вставке из буфера, создаваемая временная БД наполняется из временного файла каким-то нестандартным способом, объектам которой зачем-то присваиваются хендлы, не конфликтующие с хендлами принимающего чертежа. При этом, база получается нестандартной и поэтому не получается ее сохранить в файл. Как вам такая теория? :)

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

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

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Так по ObjectId прослеживается или нет (именно первое копирование-вставка)??

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Это я молодец, оказывается. Путь для сохранения кривой указывал.
Сохранил я эту временную БД в файл в момент ее полной инициализации, открыл - а там у объектов "правильные" хендлы.  :o

Дима_, насчет ID не понял, они в разных сеансах-то различны, не говоря уж про разные чертежи...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
И? Не знаю как Дима_, а я уже совсем запутался.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я тоже ничего не понимаю.
В соответствии с моим списком:
- создается пустая база данных (исходная БД)
- в нее читаются данные из временного ДВГ файла. Хендлы моих объектов тут правильные, судя по промежуточному сохранению
- выполняется вставка блока в чертеж (БД назначения) А вот тут хендлы уже неправильные, судя по данным из обработчиков событий
- запрашивается точка вставки
- исходная БД уничтожается
- взрывается блок

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
И? Не знаю как Дима_, а я уже совсем запутался.
Да я тоже (с учетом что паралельно как-бы работаю - но телефон свирепо насвистывает входящие emailики) - мысль про ид сейчас проверю сам и если цепочка будет покажу лог.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Код (суть скопипастил у Дмитрия):
Код - C# [Выбрать]
  1. module AcadApp
  2. open Autodesk.AutoCAD.ApplicationServices
  3. open Autodesk.AutoCAD.Runtime
  4. open Autodesk.AutoCAD.DatabaseServices
  5. open Autodesk.AutoCAD.EditorInput
  6. open Autodesk.AutoCAD.Geometry
  7.                            
  8. let Init()=
  9.   let doc=Application.DocumentManager.MdiActiveDocument
  10.   doc,doc.Editor,doc.Database,doc.TransactionManager.StartTransaction
  11.  
  12. [<CommandMethod "Test">]
  13. let Test()=
  14.   let doc,ed,db,trf=Init()
  15.   let LogedDb (db:Database)=
  16.     let PrintIdm (idm:IdMapping)=
  17.       "\nFrom "+idm.OriginalDatabase.Filename+
  18.       "\nTo "+idm.DestinationDatabase.Filename+"\n"+
  19.       (idm|>Seq.cast<IdPair>|>Seq.filter (fun idp->idp.Key.ObjectClass.DxfName="CIRCLE")
  20.           |>Seq.map (fun idp->string(idp.Key.Handle)+string(idp.Key)+"->"+
  21.                                      string(idp.Value.Handle)+string(idp.Value)+"; ")
  22.           |>Seq.reduce (+))|>ed.WriteMessage
  23.     db.BeginDeepCloneTranslation.Add(fun ev->ev.IdMapping|>PrintIdm)
  24.   Database.GetAllDatabases()|>Seq.iter (LogedDb)
  25.   Database.DatabaseConstructed.AddHandler(fun db _ ->db:?>Database|>LogedDb)
то есть смотрим как "превращаются" handl'а и id - чтобы убрать "мусор" смотрим только за кругами.
Лог (создаем круг и делаем копирование и две вставки):

Команда: _circle Центр круга или [3Т/2Т/ККР (кас кас радиус)]: *Прервано*
Команда: netload
Команда: test
Команда: _circle Центр круга или [3Т/2Т/ККР (кас кас радиус)]:
Радиус круга или [Диаметр]:
Команда: (cdr (assoc 5 (entget (entlast))))
"1FB"
Команда: _copyclip найдено: 1

From C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
To
1FB(2129671192)->4F(2129686136);

Команда: _pasteclip
From C:\Users\1F43~1\AppData\Local\Temp\A$C53B37EF2.DWG
To C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
1FD(2129686136)->1FD(2129671208); Точка вставки:
From C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
To C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
1FD(2129671208)->202(2129671248);

Команда: (cdr (assoc 5 (entget (entlast))))
"202"

Команда: _pasteclip
From C:\Users\1F43~1\AppData\Local\Temp\A$C53B37EF2.DWG
To C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
204(2129706616)->204(2129671264); Точка вставки:
From C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
To C:\Users\Дима\AppData\Local\Autodesk\AutoCAD
2010\R18.0\rus\template\acadiso.dwt
204(2129671264)->209(2129671304);
Команда: (cdr (assoc 5 (entget (entlast))))
"209"
то есть имея исходный handle 1Fb - через Id он легко прослеживается до конечного 202
1FB(2129671192)->4F(2129686136); 1FD(2129686136)->1FD(2129671208); 1FD(2129671208)->202(2129671248);
То есть мы видим, что у id 2129686136 меняеться handle (скорее он неверно определяеться при "заборе из буфера" - то есть мы запрашиваем систему handle у "неиниционизированного" объекта - он выдает "первый свободный" но т.к. он видимо не записывается - то и следующему объекту выдается тот-же - отсюда и коллизия) но это разумеется только при первой вставке (по id второй раз так не прокатит - смотри лог - появляеться "новорожденный" объект появление которого не отловленно).
Как вариант вижу только попробывать обновлять содержимое буфера при каждой вставке самим сосбой (запоминая ID объектов идущих в пустую базу).

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
У меня нет слов :)
Спасибо! Сейчас опробую и, надеюсь, что закончу эту трехдневную эпопею с поиском пропавших хендлов :)

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Дима_ Спасибо. В общем ты подтвердил то, о чем я говорил, т.е. что Handle для результирующего объекта в момент BeginDeepCloneTranslation не определен. Т.е. в этой схеме хендлы действительны только слева от ->

Фактически:
1FB(2129671192) ->  4F(2129686136);
1FD(2129686136) -> 1FD(2129671208);
1FD(2129671208) -> 202(2129671248);


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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Общими усилиями, таки, получилось :)
Сделал инструмент для добавления ссылок между объектами в чертеж.
Если объекты копировать в чертеже любыми командами: копирование, зеркало и т.п., то связи к новым объектам тоже добавляются.
Если объекты копировать в другой чертеж - аналогично.
Связи в чертеже сохраняются только после сохранения чертежа.
Исходники - в приложенном архиве. Рядом скомпилированная сборка для AutoCAD 2014 x64. При загрузке инициализируется автоматически. Командой TestAddReference можно добавить ссылку одного объекта на другой, командой TestGetReferencedObject - проверить связь объекта с другим.
В исходниках есть папка Notes - там я старался довольно подробно изложить основные идеи + подробно комментировал код.
Пока не все реализовал, что хочу, буду дальше допиливать под свои нужды.

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Код написанн красиво и главное разборчиво...
Если объекты копировать в чертеже любыми командами: копирование, зеркало и т.п., то связи к новым объектам тоже добавляются.
На этой фразе я понял, что где-то я такое уже видел - а ведь по сути то же самое реализованно в самом автокаде (интересно можно-ли воспользоваться для любых объектов, а не только для текстов и выносок), ведь если создать поле на объект, то при копировании его с целевым объектом (так-же неважно куда и как) ссылка "перерегестрируется" (будет видно при регенарции) - причем для этого ничего запущенного в памяти не нужно (то есть пара всегда будет связанна - вне зависимости на какой машине с ней работали, как копировали и пр.)

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Цитировать
Код написанн красиво и главное разборчиво...
Спасибо! IntelliSence помогал :)
А вообще, есть еще над чем поработать. Я уже сегодня нашел, что можно еще улучшить...

Цитировать
интересно можно-ли воспользоваться для любых объектов, а не только для текстов и выносок
Было бы неплохо, но вряд ли такое возможно.
Да, связь именно такая как в полях реализована. Но можно и другие виды связи сделать, и логику их поведения при копировании объектов другую прописать...

P.S. Обнаружил особенность. При создании блока в чертеже, срабатывает событие BeginDeepCloneTranslation, но при попытке получения IdMapping.OriginalDatabase возникает исключение. При этом не выскакивает никаких оповещений, но дальше приложение перестает отслеживать события баз данных, то есть, практически полностью перестает работать.

P.P.S Исправил. Исправленный исходник и сборка для AutoCAD 2014 x64 - во вложении.
Демо-ролик: https://screencast.autodesk.com/main/details/e92f1c81-99e0-4978-81fa-fbde6d21b338
« Последнее редактирование: 17-07-2014, 15:00:56 от Загорулькин Дмитрий »

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Видеопример использования связей между объектами: https://screencast.autodesk.com/main/details/af4422d2-b15f-4ab8-a62d-02d4e66563e3
Соединил выноску и блок связью, добавил отслеживание изменений связанных объектов.

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Браво! Вы наблюдательны :)
Я заметил это, когда первый вариант видео записывал. Пришлось даже остановить запись и поэкспериментировать. Все дело в том, что я использую событие CommandEnded для изменения объектов. При изменении свойств через палитру, этого события не происходит.
До этого я пробовал использовать событие Database.ObjectModified, поэтому, такой проблемы не было. Зато, была проблема при использовании команды отмены.
В принципе, ничего сильно критичного, хотя, конечно, можно придумать ситуацию, когда модификация останется необработанной.
Если подскажете, как можно отловить изменение объекта через панель свойств без использования Database.ObjectModified - буду очень признателен!

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Попробовал, не получается :(
Мне нужно в методе отклика модифицировать выноски. Когда я пытаюсь открыть объект на модификацию, выдает исключение eLockViolation.
Интересная картина получается, если попытаться заблокировать документ во время этой операции - автокад и мой плагин начинают соперничать за право блокировать документ и в итоге мой плагин сдается, вывалив ошибку :) По поведению это очень похоже на вот это: http://forum.dwg.ru/showthread.php?t=102587

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Так а если ты в DocumentLockModeWillChange просто отметишь, что нужно модифицировать, а саму модификацию произведёшь в другом событии? Например, в Editor.EnteringQuiescentState?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
То что нужно модифицировать, я отмечаю в событии Database.ObjectOpenedForModify. Пока со своими функциями справляется :)
Цитировать
Например, в Editor.EnteringQuiescentState?
В жизни не догадался бы... Я так понимаю, это какая-то реакция на "безмолвные" редактирования?
В общем, работает! Меняет, правда, не сразу, а только при переходе в чертеж из палитры свойств. Но это уже мелочи.
Спасибо!

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я так понимаю, это какая-то реакция на "безмолвные" редактирования?
Точнее реакция на то, что ничего в AutoCAD не происходит и он ожидает действия пользователя.
Меняет, правда, не сразу, а только при переходе в чертеж из палитры свойств.
Ну в этом событии именно так и должно быть.
Кстати, подозреваю, что если в DocumentLockModeWillChange ты бы проверял DocumentLockModeWillChangeEventArgs.CurrentMode и документ уже был заблокирован, то его блокировать уже не нужно и тогда ты можешь открыть объект для модификации. Если интересно - попробуй.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Попробовал. Если CurrentMode == DocumentLockMode.NotLocked - пробую блокировать документ. При этом сперва в комстроке выскакивает предупреждение, что выполняется команда, а если нажать "Повторить" - выскакивает исключение eLockChangeInProgress.
Проверил сейчас свойство Document.CommandInProgress перед блокировкой документа - пустая строка.

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Проверил порядок блокировки документа с помощью волшебной ARX-утилиты, получил такой листинг:
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Will Change]
    MyCurMode:  Not Locked
    MyNewMode:  Write | Protected Auto Write
    CurMode:    Not Locked
    CmdName:    PARTIALREGEN
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Will Change]
    MyCurMode:  Auto Write
    MyNewMode:  Not Locked
    CurMode:    Auto Write
    CmdName:    #
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Changed]
    MyPrevMode: Auto Write
    MyCurMode:  Not Locked
    CurMode:    Not Locked
    CmdName:    #
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Changed]
    MyPrevMode: Not Locked
    MyCurMode:  Write | Protected Auto Write
    CurMode:    Write | Protected Auto Write
    CmdName:    PARTIALREGEN
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Will Change]
    MyCurMode:  Write | Protected Auto Write
    MyNewMode:  Not Locked
    CurMode:    Write | Protected Auto Write
    CmdName:    #PARTIALREGEN
<DOC REACTOR: Чертеж1.dwg> : [Document Lock Mode Changed]
    MyPrevMode: Write | Protected Auto Write
    MyCurMode:  Not Locked
    CurMode:    Not Locked
    CmdName:    #PARTIALREGEN
Попробовав разные варианты (и словив кучу ошибок :)), пришел к выводу, что надо попадать в предпоследнее событие с помощью проверки:
Код - C# [Выбрать]
  1. (e.CurrentMode & DocumentLockMode.Write) == DocumentLockMode.Write
В итоге, все получилось: https://screencast.autodesk.com/main/details/be809ed7-bb4b-4afb-a322-38b29715e299
Александр Наумович, большое спасибо!

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Обнаружил интересный момент. При запуске команды _OPEN, а в диалоге выбора файла нажал отмену и словил исключение:
Код - C# [Выбрать]
  1. /// <summary>
  2.         /// Реакция на предстоящее изменение блокировки документа
  3.         /// </summary>
  4.         /// <param name="sender"></param>
  5.         /// <param name="e"></param>
  6.         static void DocumentManager_DocumentLockModeWillChange
  7.             (object sender, DocumentLockModeWillChangeEventArgs e)
  8.         {          
  9.                 Document adoc = e.Document;
  10.                
  11.                 // На всякий случай проверяем ссылку на документ
  12.                 if (adoc != null
  13.                     // и если текущий режим блокировки содержит флаг "запись"
  14.                     && ((e.CurrentMode & DocumentLockMode.Write) == DocumentLockMode.Write))
  15.                 {
  16.                     // ...
  17.                     Database = adoc.Database; // <-- тут исключение
  18.                     // ...
  19.                 }
  20.             }          
  21.         }
То, что бывают базы без документа, я знал. А вот что документ без базы - первый раз встретил!

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Эх... Смешно до слез! Сколько времени я потратил на разработку этого инструмента! Сколько багов отловили пользователи! Сколько нервов это стоило и мне и им! А оказалось, что это просто велосипед. И все уже давно сделано и работает как надо.
Принцип прост: берем Id объекта и добавляем его в запись словаря другого объекта под кодом HardPointerId или SoftPointerId. И всё, больше ничего делать не надо! Все остальное берут на себя внутренние механизмы AutoCAD! Никаких обработчиков событий, актуализаторов и прочей головной боли! :-\

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

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

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Тестирую. Пока что никаких проблем не обнаружил. Закрывал-открывал чертеж, копировал объекты через буфер и командами, чистил, экспортировал из Civil в AutoCAD... Подскажете, что надо сделать, чтобы вызвать сбой?

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Подскажете, что надо сделать, чтобы вызвать сбой?
Возможно в твоём сценарии использования связи между объектами чертежа на такой сбой никогда не попадёшь. У меня были проблемы с редактированием ручек Custom Entity, когда необходимо было обработать связанные примитивы.

P.S.: Кстати, это у тебя связи между примитивами (наследниками Entity) или между объектами (наследниками DBObject)? Если примитивами, то какая реакция на обычное копирование (команда _COPY) должна с ними быть?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Связь между примитивами.
Реакция на обычное копирование сейчас реализована таким образом, что если копируются оба объекта, то между их копиями создается новая связь. Если копируется только один объект из пары - то никакой реакции.
Во внутреннем механизме AutoCAD это реализовано немного иначе. Если объекты копируются парами - то так же как у меня, а вот если один объект из пары - то у копии появляется связь к связанному объекту оригинала.
Можете сами попробовать:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System;
  6. using System.Linq;
  7.  
  8. namespace AcadTest
  9. {
  10.     public class ObjectLinkTest
  11.     {
  12.         const string HardPointerRecordName = "HardPointer";
  13.         const string SoftPointerRecordName = "SoftPointer";
  14.         /*
  15.          * Handle не пересчитываются автоматически
  16.          * и хранятся в виде строки
  17.         const string HandleRecordName = "Handle";
  18.        
  19.          * Ownerships коды не записываются в Xrecord        
  20.         const string HardOwnershipRecordName = "HardOwner";
  21.         const string SoftOwnershipRecordName = "SoftOwner";
  22.         */
  23.  
  24.         [CommandMethod("AddSoftPointerLink")]
  25.         public void AddSoftPointerLink()
  26.         {
  27.             AddLink(DxfCode.SoftPointerId);
  28.         }
  29.  
  30.         [CommandMethod("AddHardPointerLink")]
  31.         public void AddHardPointerLink()
  32.         {
  33.             AddLink(DxfCode.HardPointerId);
  34.         }
  35.  
  36.         [CommandMethod("GetSoftPointerLinkedObject")]
  37.         public void GetSoftPointerLinkedObject()
  38.         {
  39.             SelectLinked(DxfCode.SoftPointerId);
  40.         }
  41.  
  42.         [CommandMethod("GetHardPointerLinkedObject")]
  43.         public void GetHardPointerLinkedObject()
  44.         {
  45.             SelectLinked(DxfCode.HardPointerId);
  46.         }
  47.  
  48.         static void AddLink(DxfCode code)
  49.         {
  50.             SupportMethods.InitializeVars(out Document adoc,
  51.                 out Editor ed, out Database db);
  52.  
  53.             if (!ed.SelectEntity(out ObjectId firstId, "\nSelect object for write: ")
  54.                 || !ed.SelectEntity(out ObjectId secondId, "\nSelect object for reference: "))
  55.                 return;
  56.  
  57.             WriteObjectIdToDict(firstId, secondId, code);
  58.         }
  59.  
  60.         static void SelectLinked(DxfCode code)
  61.         {
  62.             SupportMethods.InitializeVars(out Document adoc,
  63.                 out Editor ed, out Database db);
  64.  
  65.             if (!ed.SelectEntity(out ObjectId objId, "\nSelect object: "))
  66.                 return;
  67.  
  68.             ObjectId linkedId = GetObjectIdFromDict(objId, code);
  69.             if (linkedId.IsValid
  70.                 && linkedId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(Entity))))
  71.             {
  72.                 ed.SetImpliedSelection(new[] { linkedId });
  73.             }
  74.         }
  75.  
  76.         static void WriteObjectIdToDict(ObjectId objId, ObjectId writedId, DxfCode code)
  77.         {
  78.             ObjectId dictId;
  79. #pragma warning disable CS0618 // Type or member is obsolete
  80.             using (DBObject obj = objId.Open(OpenMode.ForRead))
  81. #pragma warning restore CS0618 // Type or member is obsolete
  82.             {
  83.                 dictId = obj.ExtensionDictionary;
  84.                 if (!dictId.IsValid)
  85.                 {
  86.                     obj.UpgradeOpen();
  87.                     obj.CreateExtensionDictionary();
  88.                     dictId = obj.ExtensionDictionary;
  89.                 }
  90.             }
  91.  
  92. #pragma warning disable CS0618 // Type or member is obsolete
  93.             using (DBDictionary dict = dictId.Open(OpenMode.ForWrite) as DBDictionary)
  94. #pragma warning restore CS0618 // Type or member is obsolete
  95.             using (Xrecord xrec = new Xrecord())
  96.             using (ResultBuffer resBuff = new ResultBuffer(new TypedValue((int)code, writedId)))
  97.             {
  98.                 string entryName = GetLinkRecordName(code);
  99.                 if (dict.Contains(entryName))
  100.                 {
  101.                     dict.Remove(entryName);
  102.                 }
  103.                 xrec.Data = resBuff;                                
  104.                 dict.SetAt(entryName, xrec);
  105.             }
  106.         }
  107.  
  108.         static ObjectId GetObjectIdFromDict(ObjectId objId, DxfCode code)
  109.         {
  110.             ObjectId dictId = ObjectId.Null;
  111. #pragma warning disable CS0618 // Type or member is obsolete
  112.             using (DBObject obj = objId.Open(OpenMode.ForRead))
  113. #pragma warning restore CS0618 // Type or member is obsolete
  114.             {
  115.                 dictId = obj.ExtensionDictionary;
  116.             }
  117.  
  118.             string entryName = GetLinkRecordName(code);
  119.  
  120.             if (!dictId.IsValid) return ObjectId.Null;
  121.  
  122.             ObjectId xrecId = ObjectId.Null;
  123.  
  124. #pragma warning disable CS0618 // Type or member is obsolete
  125.             using (DBDictionary dict = dictId.Open(OpenMode.ForRead) as DBDictionary)
  126. #pragma warning restore CS0618 // Type or member is obsolete
  127.             {
  128.                 if (dict.Contains(entryName))
  129.                 {
  130.                     xrecId = dict.GetAt(entryName);
  131.                 }
  132.             }
  133.  
  134.             if (!xrecId.IsValid) return ObjectId.Null;
  135.  
  136. #pragma warning disable CS0618 // Type or member is obsolete
  137.             using (Xrecord xrec = xrecId.Open(OpenMode.ForRead) as Xrecord)
  138. #pragma warning restore CS0618 // Type or member is obsolete
  139.             using (ResultBuffer resBuf = xrec.Data)
  140.             {
  141.                 TypedValue[] tVals;
  142.                 if (resBuf != null && (tVals = resBuf.AsArray()).Length > 0)
  143.                 {
  144.                     object val = tVals.FirstOrDefault
  145.                         (item => item.TypeCode == (int)code).Value;
  146.                     if (val != null && val is ObjectId id)
  147.                     {
  148.                         return id;
  149.                     }
  150.                 }
  151.             }
  152.             return ObjectId.Null;
  153.         }
  154.  
  155.         static string GetLinkRecordName(DxfCode code)
  156.         {
  157.             switch (code)
  158.             {
  159.                 case DxfCode.HardPointerId:
  160.                     return HardPointerRecordName;
  161.                 case DxfCode.SoftPointerId:
  162.                     return SoftPointerRecordName;
  163.                 default:
  164.                     throw new ArgumentException("Undefinded dxf code");
  165.             }
  166.         }
  167.     }
  168.  
  169.     static class Support
  170.     {
  171.         public static void InitializeVars(out Document adoc, out Editor ed, out Database db)
  172.         {
  173.             adoc = Application.DocumentManager.MdiActiveDocument;
  174.             ed = adoc.Editor;
  175.             db = adoc.Database;
  176.         }
  177.  
  178.         public static bool SelectEntity(this Editor ed, out ObjectId id, string msg = "\nSelect entity: ")
  179.         {
  180.             PromptEntityResult entRes = ed.GetEntity(msg);
  181.             id = entRes.ObjectId;
  182.             return entRes.Status == PromptStatus.OK;
  183.         }
  184.     }
  185. }
  186.  

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

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

Оффлайн Кирилл Захаров

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Желательно сразу включить запись лога в файл, так как будет очень много сообщений
Извините, не относится к теме обсуждения.
Александр, подскажите пожалуйста как включить запись лога в файл в ARXDBG.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Александр, подскажите пожалуйста как включить запись лога в файл в ARXDBG.
Так это же стандартный AutoCAD'овский log-файл. Т.е. включается/выключается командами _LOGFILEON/_LOGFILEOFF
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Кирилл Захаров

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Спасибо, Александр. Не знал об этой команде

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Спасибо, Александр. Не знал об этой команде
Есть еще системная переменная LOGFILEPATH для задания пути к log-файлу: http://help.autodesk.com/view/ACD/2017/RUS/?guid=GUID-0E2D4DF2-4C26-48AC-ACBC-819E3C46CE59
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение