Кривые Безье
- Войдите на сайт для отправки комментариев
Пнд, 27/08/2018 - 11:39
Добавил в библиотеку Adafruit_GFX функции для вывода элементов векторной графики.
Кривые безье по трем и четырем точкам.
Добавил в библиотеку Adafruit_GFX функции для вывода элементов векторной графики.
Кривые безье по трем и четырем точкам.
Измененные файлы библиотеки Adafruit_GFX
Демо код
Молодец! Замечания нужны? Или ну их нафиг?
На Ваше усмотрение.
Знаю что код кривоват и на костылях.
Ну, тогда нафиг. Захотите - обратитесь.
С помощью онлаин векторного редактора получил координаты кривых и опорных точек векторного изображения "Рыба"
занес эти данные в массив и написал небольшой код который переберая массив с координатами строит изображение
в дальнейшем оформлю в отдельную функцию которая будет принимать ссылку на массив с данными и строить по ним изображение с заданным масштабом в заданных координатах и с произвольным углом наклона.
Немного подкорректировал функции построения кривых в измененной библиотеке Adafruit_GFX (ссылка в перврм посте)
Пример функции построения кривой Безье по четырем точкам.
Вот что получилось. В верхнем левом углу время в мс затраченое на прорисовку
Без оптимизации - шаг 1%
С шагом 5%
С шагом 10%
С переменным шагом в зависимости от протяженности кривой
С шагом 100% - просто прямыми
Встала задача написать парсер или конвектор векторных файлов SVG в вид пригодный для вставки в код (массив с координатами и типом объектов. Например в коде выше перед кривой безье 4го порядка в массиве стоит 4).
Если кто сталкивался с таким вопросом подскажите существует ли какойнибудь настраиваемый конвтер под свои нужды или это можно провернуть в Excel или еще какими инструментами. Может кто ради спортивного интереса...
SVG фаил Рыбки
Встала задача написать парсер или конвектор векторных файлов SVG в вид пригодный для вставки в код (массив с координатами и типом объектов. Например в коде выше перед кривой безье 4го порядка в массиве стоит 4).
я так понял, что внутри SVG этот массив уже есть, задача состоит только в переводе длинных числе с десятичной точкой в целые?
ну и еще - в практике векторной графики кривые Безье практически не используются - слишком накладно при выводе на устройство вычислять эту математику. Обычно кривые в картинке еще на этапе формирования файла заменяются на серии отрезков с нужным разрешением. Особенно это актуально, имхо, для ардуины. Так что имеет смысл подумать о том, чтобы прямо в конвертере менять кривые Безье на отрезки.
У меня так и высчитываются не все точки кривой, а с опрелеленным шагом, а между ними прямые строятся. На картинках выше влияние шага между точками на качество.
Хранить координаты начала, конца и опорных точек дешевле чем все точки перегиба ломаной.
ну тут выбор - либо хранить больше точек, но рисовать их быстрее, либо хранить меньше, но зато считать в процессе.
Если точки хранить то при увеличение масштаба будут видны точки перегиба
На просторах всемирной нашел слелующий мануал по SVG https://svg-art.ru/?page_id=907
Буду курить.
Продолжаю игру в одни ворота.
На электронных таблицах сделал небольшой парсер SVG.
В ячейку A1 вставляется текст из фала SVG (строка с описанием <path), далее удаляютя лишние атрибуты,пробелы заменяютя на ",", служебные символы заменяются на коды команд для прорисовки кривых и линий.
В итоге в ячейке А15 получаем строку пригодную для вставли в код.
Пример
Все еще очень сыро (предстоит еще много работы), не все команды выполняютя. На данный момент гарантированно выводятся изображения состоящие из кривых Безье четвертого порядка.
yul-i-an, если я правильно понял, пока ваш парсинг SVG заключается лишь в замене буквы "C" на цифру "4"?
Мне кажется вы не с того начали. Как раз букву "С" я бы из массива не убирал. Ваша идея кодировать начало кривой Безье просто цифрой "3" или "4" - на мой взгляд не слишком удачна, можно перепутать с координатами. Почему бы не оставить кодирование буквами, как это сделано в SVG - тогда и обработка этих данных в программе будет понятнее и проще.
Гораздо важнее конвертировать дробные координаты точек в целые, не потеряв точности.
yul-i-an, если я правильно понял, пока ваш парсинг SVG заключается лишь в замене буквы "C" на цифру "4"?
Мне кажется вы не с того начали. Как раз букву "С" я бы из массива не убирал. Ваша идея кодировать начало кривой Безье просто цифрой "3" или "4" - на мой взгляд не слишком удачна, можно перепутать с координатами. Почему бы не оставить кодирование буквами, как это сделано в SVG - тогда и обработка этих данных в программе будет понятнее и проще.
Гораздо важнее конвертировать дробные координаты точек в целые, не потеряв точности.
На грабли с совпадением координат и команд я уже наступал, теперь просто если допустим код 4 это значит кривая 4 порядка, задается 4мя парами координат, значит следующий код команды будет через 7 ячеек массива и т.д.
Про дробные тоже пока думаю, надо алгоритм отработать пока.
На грабли с совпадением координат и команд я уже наступал, теперь просто если допустим код 4 это значит кривая 4 порядка, задается 4мя парами координат, значит следующий код команды будет через 7 ячеек массива и т.д.
ну тогда хотя бы перед теми числами, которые на самом деле не цифры, а команды - вставляйте перевод строки:
хотя я оставил бы букву С - так удобнее
Честно говоря, не пойму, нафига это надо. Полный интерпретатор SVG для ардуины будете писать?
Началось с добавления кривых Безье в Adafruit_GFX, ну раз кривые есть то и векторную графику выводить можно.
Полный интепритатор писать не буду, там очень много нюансов, а вот иконки для меню, логотипы и т.п. выводить, особенно если масштабировать необходимо, допустим меню листаем крупные иконки, при входе впункт меню иконку уменьшаем в уголок. Чтобы бинарные картинки не хранить...
Да и академический интерес присутствует.
Думал может на G код переключится... Дальше видно будет.
Помогите не замыленым глазом, сам уже с толку сбился.
Работает
Не работает
Если вынести прирощение шага за IF то все ок, если приращивать в IF то не работает. Разницы не вижу.
Смысл такой хотел - в зависимости от содержания fish[st] и выполнения соответсвующего действия перемещатся на определенный шаг.
Хотел примерно так
А дисплей какого разрешения Вы собираетесь использовать совместно с Ардуиной?
(Это к тому, что все универсальные решения - неоптимальны. Иногда - сильно неоптимальны)
А дисплей какого разрешения Вы собираетесь использовать совместно с Ардуиной?
(Это к тому, что все универсальные решения - неоптимальны. Иногда - сильно неоптимальны)
Это я понимаю. Думаю раз начал надо добить до стабильной работы, темболее кое какие результаты получены.
Но с кодом из поста выше всеравно недоганяю - какая разница где прирашивать шаг в IF или за его прилом?
В общем парсер особо и не понадобился
В дефайнах определил команды SVG, и лишние пробелы заменил на запятые в NotePad++
Векторный редактор вызает файлы в абсолютной системе координат
Остались проблеммы с выводом S кривых (описание SVG команд)
Необходимо добавить квадрат, круг, эллипс и т.п.
Длинные комбинации команд приводят к зависанию...
Длинные комбинации команд приводят к зависанию...
Неаккуратки с памятью?
А про вывод крупных шрифтов не думали? А то в растровых очень расточительно получается крупные буквы хранить.
Сегодня думал уже. Надо както все это дело оптимизировать.
С контурами шрифтов проблем не будет, а вот для заливки надо буфер делать в нем строить контур, заливать и выводить как битмап.
Слона едят по частям. Сразу бы контуры. Или толстой линией. Может и так годно окажется. А уж потом, если не очень, и про заливку подумать.
Длинные комбинации команд приводят к зависанию...
Неаккуратки с памятью?
Подскажите что можно предпринять.
Хочу прорисовку попробовать как в этой статье
Ну, как я могу подсказать,это надо садиться и погружаться в код с головой. так с наскоку чего там наподсказываешь.
Вот отыскал инфу по векторнфм шрифтам https://m.habr.com/post/119608
Попробовал выводить векторные цифры. Пришлось отрисовать цифры в векторном редакторе. Вот что примерно получилось
выводил шум АЦП
ВИДЕО
Код
Думаю к кодеровке символов нужно добовлять информацию о ширине символа для расчета отступов (если шрифт не моноширинный)
Помоему и так очень неплохо. И 11-12 мсек - хороший результат. Жаль сейчас совсем нет времени, а то бы поигрался и я.
Посмотрел поподробней. Цифры прорисованы исключительно прямыми. Это имеет свои + и -. Минус в том, больше примитивов и менее качественная картинка. Но зато общет прямых быстрей и можна толщину линии у буквы менять просто проведя вместо одной линии несколько паралельных на малом расстоянии.
Вобщем думаю что на прямых - нормально.
Для повышения качества символа и экономии места интересно иметь кодировки отдельных элементов символов в виде "библиотеки", т.е. отдельно качественно прорисовать кружки, дуги и т.д и хранить их один раз гдето в одном месте. Ну понятно что нижний круг у "8" и у "6" одинаковы, зачем его каждый раз описывать, достаточно сослатся, например при прорисовки "8" на последовательность команд рисующих нижний кружек для "6". А для "5" возможно взять часть из этого кружка.... Или хранить отдельно загогулину "5" и отдельно недостающую этой загогулине до кружка часть. Тогда загогулина "5" будет использоватся для "3", "5", "6", "8", но для "6" и "8" к ней недостающее добавится. Ну и буквы "S", "d" и т.д уже не потребуют подробного описания этих мест. Наверно это уже не совсем SVG будет, а SVG++ )))
//информацию о ширине символа для расчета отступов (если шрифт не моноширинный)
Ну моноширотный у растровых никого не смущает. А если очень хочется - ширину символа легко определить по ходу прорисовки.
Эти дни эксперементировал, закончилось все тем что катострофически не хватает памяти. Необходимо описание символов переносить в PROGMEM или сжимать, и распоковывать по необходимости.
Код кому интересно
функция вывода чисел (эксперемент)
Функция вывода текста
Функция прорисовки кривых
В принципе реально все сделать, но нужно продумать оптимизацию. Векторный текст крупного размера выглядит более привлекательно чем растровый ИМХО.
В итоге мой OLED 128х64 "надул кеды" как говорится. Стал показывать черезстрочно растягивая изображение по вертикали.
Пришлось эксперемент оставить.
Идет зима, есть более важные задачи по отоплению. Экран заказан новый, будем подождать.
Кому интересно можете развить идею.
В итоге мой OLED 128х64 "надул кеды" как говорится. Стал показывать черезстрочно растягивая изображение по вертикали.
кстати, так тоже неплохо...
ИМХО, сама идея не слишком подходит для МК. вычислять кривые Безье в реале, чтобы только построить текст - это что-то из разряда многократноизбыточного кода, типа Гугля.
ИМХО, более плодотворная идея - на основе КБ на ПК написать генератор векторных шрифтов для ардуины, которым под конкретный дисплей генерить готовые к применению шрифты нужных размеров в виде традиционного битового массива.
С растровыми шрифтами, т.е. "в виде традиционного битового массива" хоть правильней их таки растровыми называть, все класно пока они мелкие 5*8, 8*12. А когда крупные нужны - плохо. Например 30*48 - это 180 байт на символ. Только цифры и минимум символов - уже на пару КБ, еще ладно, а буквы уже десятки КБ, невлазят в МК. Приходится масштабировать, так вылазят угловатые кубики вместо пикселей :( А векторные тут выручили бы конкретно.
Большие растровые шрифты можно легко сжать простеньким и достаточно эффективно реализуемым Хаффманом - отлично сжимаются.
Вчера тоже думал над двухступенчатым сжатием. Сначала пары 00-А 01-B 10-C 11-D а потом Хаффманом.
Хотя может подход не совсем верный.
Вот если на внешней памяти разместить шрифты то проблемм не будет. Или их както в PROGMEM затолкать, но не пробовал там както мутно для меня все.
Однозначно надо, в любых вариантах только в PROGMEM.
Разбирался с PROGMEM. В итоге память заметно освободилась (пока только цифры перенес).
Написал такой код
Теперь его нужно в функцию оформить в которую будет передаватся ссылка на массив. Сообразить не могу как.
А так что не работает
Нет. Так не получается.
Хотел так передавать
Вот так заработало если так можно выразится, виснет после каждого вывода
Чтение из PROGMEM
Надо думать дальше...
Нашел ошибку в посте #40 в первом листинге в функцию PMRead передовал длину массива для всех цифр от dig0. Исправил на соответствующие, все заработало.
Итог - вывод 10 символов занимает от 7-11 мс в масштабе 0.7, в масштабе 1:1 9 символов 4-6мс
Полностью ввел заглавные латинские и цифры
Видео
Дисплею совсем поплохело, через не продолжительное время работы мерцать стал, хотя может код виновен... Ели у кого появится желание проверить отпишитесь о результате
Если что по упрощению есть предлогайте.
Помоему на видео просто великолепно!
Упрощать есть что. Нужно завести массив указателей, пусть
simbols
, на массивы от spase до lz. Это позволит избавится от длинного свича, заменив его наPMRead(simbols[
Если порыть либы то найдется коечегоsym-32
]);типа
#define PGM_P const prog_char *
#define PGM_VOID_P const prog_void *
extern PGM_VOID_P memchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__;
extern int memcmp_P(const void *, PGM_VOID_P, size_t) __ATTR_PURE__;
extern size_t strlcpy_P (char *, PGM_P, size_t );
extern size_t strlen_P(PGM_P) __ATTR_CONST__; /* program memory can't change */
И т.д.
Я себе массив указателей на строки в progmem так делал.
Вам массив указателей не на строку а на массив, оно будет подобным.
И длину передавать не нужно, прочто цикл стр.185-189 вести не по условию длины, а пока не прочитаем 0. Гдето так.
Спасибо за информацию. Буду копать дальше. Пока с выводом переменных заморачивался.
Костыль на костыле. Может кто преобразовываль числа с плавающей точкой в строки?
Этого валом в сети, первое попавшее https://www.geeksforgeeks.org/convert-floating-point-number-string/
Разобрался со своим экраном, оказалось после обновления библиотеки неправильное разрешение было выставлено.
Сейчас добавляю недостающие символы к шрифту.
Видео прорисовки векторного шрифта на OLED (умышленно замедленное программно)
Код кому интересно
Надо все это дело в отдельную библиотеку завернуть чтобы пользоватся проще было
Попробовал написать растеризатор векторных шрифтов.
В итоге буфер под символ жрет память, вывод на дисплей символа 10х10 точек с заливкой занимает примерно 9-10 мс.
Инфу брал тут.
Дошли руки, потестил с экраном SH1106, походу правил т.к. ребутилось. На таком скетче отрисовует за 15-17мсек. Очень симпатично выходит. Жаль времени нет с безобразным свичем разделатся. Есть еще идеи по сжатию, но позже.
Только закончил весь латинский
и switch дополнил
Еще сделал переход на новую строку если текст не лэзет и переход на новую строку после вывода аналог println в конце DrawVector добавил
Весь код
Переход на новую строку думаю не требуется, при проектировании вывода на экран, тем более такой небольшой, все сразу четко по строкам разделяют.