Сообщество программистов Autodesk в СНГ
ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 14-12-2018, 14:00:14
-
Словил ещё один интересный момент при работе с расширенными данными. Чем-то эта ситуация напоминает ситуацию с длинными строками в XData.
В моём плагине решил использовать значение Double.NaN для обозначения того, что величина не задана и берётся по умолчанию. Провёл опыты - пишется и читается это значение без проблем под кодом DxfCode.ExtendedDataReal:
(https://i.postimg.cc/qNTQ0gTh/20181214-xdatanan.png) (https://postimg.cc/qNTQ0gTh)
И всё было хорошо, пока я не запустил команду AUDIT:
Команда: _AUDIT
Исправить все обнаруженные ошибки? [Да/Нет] <Н>: Д
Проверка заголовка
Проверка таблиц
Проверка объектов, проход 1
Проход 1: проверено объектов: 11000 XData 1040 0 НеЧисл 0
Проход 1: проверено объектов: 11100 XData 1040 0 НеЧисл 0
Проход 1: проверено объектов: 11400
Проверка объектов, проход 2
Проход 2: проверено объектов: 11400
Проверка блоков
Проверено блоков: 181
Проверка AcDsRecords
Всего найдено ошибок: 2, исправлено: 2
Стерто 0 объектов
Все мои NaN она заменила на нули. После этого мои объекты, которые использовали это значение для отрисовки, стали выглядеть крайне неприглядно :(
В связи с этим, вопросы:
- Можно ли считать это багом? Или считать это такой особенностью поведения?
- Какое-бы значение записать сюда, чтобы идентифицировать его как "не задано"? Просто не записать ничего - не могу. Я использую строгий порядок данных и доступ к ним по их порядковому номеру. И если какое-то из них пропустить, то это нарушит работу с остальными данными.
-
Сейчас у себя в xdata записываю строку json, разбитую по 255.
-
Ну это - да, уже давно известное ограничение длины строк в XData. Последний раз совсем недавно (http://adn-cis.org/forum/index.php?topic=8951.0) обсуждали.
А вот про NaN в XData я ещё нигде не встречал и гугл ничего про это не нашёл.
-
Я бы не стал использовать double.NaN в принципе. Автокад появился в 1983 году и вроде практически сразу имел расширенные данные, а вот Net framework появился в 2002. Логично предположить, что такого обозначения невалидных значений как double.NaN просто не было и в автокаде они не предусмотрены
-
Ок, согласен, логично :) Значит, это не баг, а особенность, появившаяся вследствие исторических причин.
Есть идеи насчёт второго вопроса?
-
- Можно ли считать это багом? Или считать это такой особенностью поведения?
Это однозначно не баг. Ты использовал недопустимое значение.- Какое-бы значение записать сюда, чтобы идентифицировать его как "не задано"?
Увы, но тут подсказать что-то сложно. Нужно знать в каком диапазоне может быть значение. Например, вряд ли значение из нашей реальной жизни может быть > 1e+101. Вот и можешь его использовть как маркер. Если > 1e+100 тогда "неопределено".
-
Кстати, в ResultBuffer ведь в любом случае отправляется object. Что будет, если записать вообще не число, а, например, строку? На этапе компиляции ведь это будет можно. Вопрос только в том, как поведёт себя Автокад? Если можно провернуть такой трюк, то при чтении данных достаточно double.TryParse
-
Нужно знать в каком диапазоне может быть значение. Например, вряд ли значение из нашей реальной жизни может быть > 1e+101. Вот и можешь его использовть как маркер. Если > 1e+100 тогда "неопределено".
У меня там хранится высотная отметка, так что, в принципе, можно брать любое значение выше Эвереста или ниже Марианской впадины :)
Кстати, в ResultBuffer ведь в любом случае отправляется object. Что будет, если записать вообще не число, а, например, строку? На этапе компиляции ведь это будет можно. Вопрос только в том, как поведёт себя Автокад? Если можно провернуть такой трюк, то при чтении данных достаточно double.TryParse
Audit это тоже в 0 превратит.
Но если развить эту идею, то есть вариант использовать строку вместо числа. И число хранить в виде текста под кодом DxfCode.ExtendedDataAsciiString.
Мне ещё в голову пришла идея, что можно добавить в XData ещё одну TypedValue, например типа DxfCode.ExtendedDataInteger16, в которой хранить флаг использования значения: 0 - использовать значение отметки по умолчанию, 1 - использовать заданное значение отметки.
Итого, у меня сейчас есть три идеи:
- Вариант от Александра Наумовича: Число из диапазона недопустимых значений, которое точно никогда не будет использоваться.
- Вариант от Александра Пекшева: Число в виде строки.
- Мой вариант: Дополнительное TypedValue как флаг использования.
Любая из них вполне рабочая, осталось только выбрать какую использовать.
-
Любая из них вполне рабочая, осталось только выбрать какую использовать.
Мой вариант самый компактный (меньше всего байт) и самый быстрый (не требуется конвертация из строкового в плавающее). :)
-
Хмм. Это убийственные аргументы! В данном случае мне нечего возразить :)
А Вы случаем не знаете, какое ограничение сверху/снизу для вещественного числа в XData? Что-то нигде не могу информацию эту найти...
-
А Вы случаем не знаете, какое ограничение сверху/снизу для вещественного числа в XData? Что-то нигде не могу информацию эту найти...
Думаю, что это стандартное ограничения для double: Double.MinValue и Double.MaxValue
-
Я реализовал хранение строкой в виде json, как выше писал Вильдар. Собственно говоря, он и сподвиг меня к этой идее. И в этом есть свои плюсы, но они зависят уже от архитектуры приложения. Дело в том, что я у себя сделал базовый класс для всех своих примитивов, в котором и реализовано сохранение\чтение расширенных данных. При этом вся эта работа производится через рефлексию, а нужные данные помечаются специальными атрибутами. Таким образом, при разработке новых примитивов меня вообще больше не заботит вопрос о расширенных данных - я создаю новый класс, добавляю свойства, помечаю их атрибутами и все - все остальное уже работает. Таким образом я просто сосредотачиваюсь только на логике работы примитива. Но повторюсь - зависит от архитектуры приложения.
Конечно, самый главный минус - ограничение в 16к. Однако, это ограничение "пугает" только в одном случае - когда примитив может содержать множество точек - есть вероятность, что можно перевалить за предел. В других случаях я точно знаю, что переполнения не произойдет, так как количество данных заведомо известно.
Ну а скорость работы при десериализации и парсинге столь незначительны, что их просто не заметишь. Благо, сейчас не 80-ые и проблем с вычислительными мощностями нет
-
Я реализовал хранение строкой в виде json, как выше писал Вильдар. Собственно говоря, он и сподвиг меня к этой идее. И в этом есть свои плюсы, но они зависят уже от архитектуры приложения. Дело в том, что я у себя сделал базовый класс для всех своих примитивов, в котором и реализовано сохранение\чтение расширенных данных. При этом вся эта работа производится через рефлексию, а нужные данные помечаются специальными атрибутами. Таким образом, при разработке новых примитивов меня вообще больше не заботит вопрос о расширенных данных - я создаю новый класс, добавляю свойства, помечаю их атрибутами и все - все остальное уже работает. Таким образом я просто сосредотачиваюсь только на логике работы примитива. Но повторюсь - зависит от архитектуры приложения.
Ах вот оно что! Я, оказывается, не понял о чём Вильдар написал. То есть, вы решили "не париться" и обойтись только одним типом данных - строкой. Конечно же, это очень универсальный подход! Есть подозрение, что так вы займёте гораздо больше места в XData, чем если бы распределяли данные так, как это изначально задумано. Но, возможно, что это адекватная цена за облегчение разработки. В целом, идея интересная!
я точно знаю, что переполнения не произойдет, так как количество данных заведомо известно
Тут главное, чтобы ещё кто-то не стал писать в Xdata свои данные - объём-то на всех один.
-
Я так подумал: а что вам мешает сделать то же самое, но не с json и строками, а со стандартным способом размещения данных в xdata? Просто будет формироваться не массив typedvalue из строк, а из данных по типам. Не пробовали? Или тут есть какая-то сложность, которой я не вижу?
-
Я так подумал: а что вам мешает сделать то же самое, но не с json и строками, а со стандартным способом размещения данных в xdata? Просто будет формироваться не массив typedvalue из строк, а из данных по типам. Не пробовали? Или тут есть какая-то сложность, которой я не вижу?
Не могу отвечать за Вильдара - мы хоть и работаем вместе, но занимаемся разными проектами )) Не знаю, что он там делает
Отвечу за себя - при сохранении данных по типам ведь данные никак не идентифицируются. Если сохранить несколько числовых данных, то как потом понять от каких они свойств?
-
По положению в массиве. Индекс положения можно в атрибуте задавать для надёжности и возможности расширения количества данных в будущем. Я практически так и делаю сейчас.
-
По положению в массиве. Индекс положения можно в атрибуте задавать для надёжности и возможности расширения количества данных в будущем. Я практически так и делаю сейчас.
Я так и делал. В итоге у меня для каждого моего примитива приходилось реализовывать методы чтения\записи, так как у каждого примитива свой свойства и свои положения в массивах. Было много повторяющегося (точнее - похожего) кода. К тому-же, что делать с примитивами, у которых неизвестное количество точек?
Конечно, можно было как-то это реализовать все теми-же атрибутами, но было бы все-равно много мороки и мест, потенциально ошибочных - не тот индекс указал и все сломалось. В общем я подумал и решил остановится на использовании строковых значений.
Но как я писал выше - все зависит от архитектуры приложения. Да и от предпочтений разработчика. А что касаемо "наилучшего" варианта - то скорее всего его просто нет. Все варианты имеют плюсы и минусы