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

ADN Club => AutoCAD .NET API => Тема начата: avc от 29-09-2017, 16:34:30

Название: Записать ObjectId в XData
Отправлено: avc от 29-09-2017, 16:34:30
Что-то я туплю наверно. Надо в xData одного объекта сохранить идентификатор другого. Вроде где-то видел, вроде все просто было...
Записывать наверно надо Handle как-то так:
Код - C# [Выбрать]
  1.     public static void AddVal(this ResultBuffer rb, ObjectId value)
  2.     {
  3.       rb.Add(new TypedValue((int)DxfCode.ExtendedDataHandle, value.Handle));
  4.     }
Или какой код DxfCode?
А считывать? Как из Handle получить ObjectId? Конструктора такого у ObjectId нет. Есть Database.GetObjectId, но ему еще какой-то идентификатор нужен...
Название: Re: Записать ObjectId в XData
Отправлено: Александр Пекшев aka Modis от 29-09-2017, 16:39:53
А в чем проблема взять ObjectId как строку и сохранить её в XData как строку?
Название: Re: Записать ObjectId в XData
Отправлено: avc от 29-09-2017, 16:42:32
А в чем проблема взять ObjectId как строку и сохранить её в XData как строку?
Не кошерно :) Собственно, с тем же успехом можно и как long сохранить. Но как считать обратно-то?
Название: Re: Записать ObjectId в XData
Отправлено: Александр Пекшев aka Modis от 29-09-2017, 16:50:42
Ну раз не кошерно, то вот пример:
1. Сохранение:
Код - C# [Выбрать]
  1.  vals = new TypedValue[] {
  2.                             new TypedValue(
  3.                                 (int)DxfCode.ExtendedDataRegAppName,
  4.                                 xDataAppName),
  5.                             new TypedValue(
  6.                                 (int)DxfCode.ExtendedDataAsciiString,
  7.                                 line.Handle.ToString())
2. Чтение:
Код - C# [Выбрать]
  1. if (!string.IsNullOrEmpty(handleString))
  2.                     {
  3.                         ObjectId entId =
  4.                             CadHelper.GetObjectIdFromHandleString(
  5.                             dbObject.Database, handleString);
  6.  
  7.                         if (!entId.IsNull)
  8.                         {
  9.                             _changeOtherEntity = true;
  10.                             _overruleAction(entId, dbObject);
  11.                             _changeOtherEntity = false;
  12.                         }
  13.                     }
3. Преобразование:
Код - C# [Выбрать]
  1. public static ObjectId GetObjectIdFromHandleString(
  2.             Database db, string handleString)
  3.         {
  4.             ObjectId id = ObjectId.Null;
  5.  
  6.             Handle hdl =
  7.                 new Handle(Int64.Parse(
  8.                 handleString,
  9.                 System.Globalization.NumberStyles.HexNumber));
  10.  
  11.             id = db.GetObjectId(false, hdl, 0);
  12.  
  13.             return id;
  14.         }
Взято отсюда (http://drive-cad-with-code.blogspot.ru/2014/08/using-objectoverrule-to-force-entities.html). Там и видео и исходник есть
Название: Re: Записать ObjectId в XData
Отправлено: avc от 29-09-2017, 17:02:39
Странно, что нет прямого пути, ведь изрядная доля всех словарей в БД заполнена ссылками на объекты. Ну раз нет, то пойдем в обход. Собственно, все чего мне не хватало - это
Код - C# [Выбрать]
  1. id = db.GetObjectId(false, hdl, 0);
Значит просто нолик последний непонятный параметр.
Спасибо!
Название: Re: Записать ObjectId в XData
Отправлено: Дмитрий Загорулькин от 29-09-2017, 17:21:12
А в чем проблема взять ObjectId как строку и сохранить её в XData как строку?
В новой сессии все ObjectId пересчитываются и, соответственно, записанные таким образом данные становятся недействительными.

По теме:
http://spiderinnet1.typepad.com/blog/2012/11/autocad-net-xdata-xdata-handle-implications.html
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 29-09-2017, 17:24:13
Собственно, все чего мне не хватало - это
Код - C# [Выбрать]

    id = db.GetObjectId(false, hdl, 0);

Значит просто нолик последний непонятный параметр.
лучше
Код - C# [Выбрать]
  1. Boolean isValidHandle = db.TryGetObjectId(hdl, out id);
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 29-09-2017, 20:57:03
Странно, что нет прямого пути, ведь изрядная доля всех словарей в БД заполнена ссылками на объекты. Ну раз нет, то пойдем в обход.
В расширенных данных (Xdata) нельзя хранить ссылки на ObjectId в отличие от XRecord. Хранение Handle в ExtendedDataAsciiString имеет свои плюсы и минусы. Например, команда _WBLOCK создаёт новый чертеж с пересчитанными метками. В  ExtendedDataAsciiString метка пересчитана не будет и вероятнее всего она будет ссылаться или на неправильный объект или вообще на "ничто". Хранение в ExtendedDataHandle имеет тоже свои недостатки. При _WBLOCK метки пересчитаются, а вот что будет при обычной операции копирования? В этом случае метка не пересчитается и новый примитив будет ссылаться на оригинал, а не на копию. Так что потребуется еще некая логика обработки таких ситуаций.
Название: Re: Записать ObjectId в XData
Отправлено: avc от 29-09-2017, 22:55:43
Спасибо. Я отчетливо понимаю проблемы связанные с хранением ссылок и до сих пор мне удавалось избежать этого. Подумаю как избежать и в этот раз.
А если я попытаюсь хранить пары id связанных объектов в словарях. Это улучшит ситуацию? Какие типы DxfCode предпочтительно использовать?
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 29-09-2017, 23:20:17
А если я попытаюсь хранить пары id связанных объектов в словарях.
Не думаю. В любом случае есть проблемы логики. Универсального решения нет и быть не может.
Название: Re: Записать ObjectId в XData
Отправлено: RevitTormentor от 12-10-2017, 03:00:40
Спасибо. Я отчетливо понимаю проблемы связанные с хранением ссылок и до сих пор мне удавалось избежать этого. Подумаю как избежать и в этот раз.
А если я попытаюсь хранить пары id связанных объектов в словарях. Это улучшит ситуацию? Какие типы DxfCode предпочтительно использовать?

Этот вариант - не то?

Эх... Смешно до слез! Сколько времени я потратил на разработку этого инструмента! Сколько багов отловили пользователи! Сколько нервов это стоило и мне и им! А оказалось, что это просто велосипед. И все уже давно сделано и работает как надо.
Принцип прост: берем Id объекта и добавляем его в запись словаря другого объекта под кодом HardPointerId или SoftPointerId. И всё, больше ничего делать не надо! Все остальное берут на себя внутренние механизмы AutoCAD! Никаких обработчиков событий, актуализаторов и прочей головной боли! :-\
http://adn-cis.org/forum/index.php?topic=743.105 (http://adn-cis.org/forum/index.php?topic=743.105)
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 12-10-2017, 11:45:34
Этот вариант - не то?
Вариант не универсален, как я указывал дальше в обсуждении, хотя в некоторых случаях может быть полезен.
Название: Re: Записать ObjectId в XData
Отправлено: simson43 от 15-02-2019, 12:44:25
а если записывать все же вот так
    public static void AddVal(this ResultBuffer rb, ObjectId value)
    {
      rb.Add(new TypedValue((int)DxfCode.ExtendedDataHandle, value.Handle));
    }

то как при чтении из XData из object получить Handle, чтобы вставить его сюда?
Boolean isValidHandle = db.TryGetObjectId(hdl, out id);

следующее выдает ошибку на этапе преобразования object в Handle - заданное приведение недопустимо
Код - C# [Выбрать]
  1. Handle[] handleArr = dataList.FindAll(x => x.TypeCode == 1005).Select(x => (Handle)x.Value).ToArray();

Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 15-02-2019, 15:54:33
а если записывать все же вот так
Этого делать не следует, так как AutoCAD преобразовывает при некоторых операциях значения в группе 1005. Поэтому в какой-то момент вместо того значения, которое там было ты можешь получить совсем другое.
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 15-02-2019, 16:03:54
следующее выдает ошибку на этапе преобразования object в Handle - заданное приведение недопустимо
Код - C# [Выбрать]

    Handle[] handleArr = dataList.FindAll(x => x.TypeCode == 1005).Select(x => (Handle)x.Value).ToArray();
Думаю что вместо :
Код - C# [Выбрать]
  1. Handle[] handleArr = dataList.FindAll(x => x.TypeCode == 1005).Select(x => (Handle)x.Value).ToArray();
должно быть:
Код - C# [Выбрать]
  1. Handle[] handleArr = dataList.FindAll(x => x.TypeCode == 1005).Select(x => new Handle( Convert.ToInt64(x.Value.ToString(), 16)) ).ToArray();
Если я даже слегка в синтаксисе ошибся, то исправишь.
Название: Re: Записать ObjectId в XData
Отправлено: simson43 от 15-02-2019, 16:16:19
выше вы говорили что он пересчитывает например при WBlock.. это ведь оправданно?
или бывают случаи когда он некорректно пересчитывает?
т е лучше хранить строку?

тогда вот так сделал (сохраняю long как строку)
Код - C# [Выбрать]
  1. Handle[] handleArr = dataList.FindAll(x => x.TypeCode == 1000).Select(x => new Handle(long.Parse((string)x.Value))).ToArray();
Название: Re: Записать ObjectId в XData
Отправлено: Александр Ривилис от 15-02-2019, 16:19:45
выше вы говорили что он пересчитывает например при WBlock.. это ведь оправданно?
или бывают случаи когда он некорректно пересчитывает?
т е лучше хранить строку?

тогда вот так сделал (сохраняю long как строку)
Код - C# [Выбрать]
  1. Handle[] handleArr = typeList.FindAll(x => x.TypeCode == 1000).Select(x => new Handle(long.Parse((string)x.Value))).ToArray();

Универсального правила нет. Я не знаю для чего ты собраешься хранить Handle'ы и что будешь с ними делать, какие операции возможны с этим объектом. Как вариант можешь хранить и в группе 1000 и в группе 1005 и сравнивать результаты.
Название: Re: Записать ObjectId в XData
Отправлено: simson43 от 15-02-2019, 16:26:28
понял, спасибо!