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

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

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

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

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

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

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

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

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

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

  • 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
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Андрей. Что делать с моим пунктом 2) и как это обрабатывается указанным кодом?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

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

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

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


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

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

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

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

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

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

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

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

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

  • ADN
  • *
  • Сообщений: 1189
  • Карма: 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
  • *****
  • Сообщений: 1115
  • Карма: 173
Я бы не стал делать ставку на РД:
1. Всего 16 кб данных. И этот объем делится на все приложения.
2. Слишком легко снести / отредактировать
Будь у меня выбор, я бы остановился на словарях и словарных записях.

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

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

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

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

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

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

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

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

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