Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Текст по дуге: абсурд в вычислениях 
:(
    Опции темы
wowka19
Дата 7.5.2014, 01:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Фрагмент метода вывода текста по дуге:
Код

    qreal angle = 0;
    QFontMetricsF fm(font_);
    QTransform matrix;

    foreach (QChar ch, text_)
    {
        qreal deltaAngle = atan(fm.width(ch) / radius_) * 180/M_PI; // 1

        matrix.reset();
        matrix.translate(radius_, fm.height()); //temp
        matrix.translate(0, radius_);
        matrix.rotate(angle);
        matrix.translate(0, -radius_);
        matrix.rotate(deltaAngle/2);
        painter.setWorldTransform(matrix);
        painter.drawText(0,0, ch);

        angle += deltaAngle;
    }

    qDebug() << angle / 360 * 2*M_PI*radius_; (2)
    qDebug() << fm.width(text_); (3)


Вывожу текст по дуге окружности. Для этого я, исходя из радиуса и ширины символа, вычисляю длину хорды отдельно для каждого символа, равную ширине этого символа (QFontMetricsF::width(QString)) (1), тем самым добиваясь одинаковых промежутков между символами.
Далее я вывожу длину всей дуги, вычисленную исходя из угла охвата всей надписи и радиуса (2).
Еще ниже я вывожу длину всей надписи, которая по сути равна сумме всех хорд (3).
А теперь главное: длина надписи (сумма всех хорд) всегда больше длины дуги, что явно невозможно - должно быть ровно наоборот (хорда всегда меньше дуги). Вопрос что не так?

P.S: Экспериментально выяснил, что "врет" именно второй вывод (3). Думал проблема из-за особенностей в методе fm.width(), но это не так - ведь его же я использую и при расчете хорды (1), и сумма ширин символов совпадает с шириной всего текста.

P.P.S: Интересно, что при увеличении радиуса разница между выводами стремится к нулю, что в принципе правильно - дуги при неизменных ширин символов становятся все короче и короче. Но дуга должна быть всегда больше хорды, но это, как я уже писал выше, не выполняется.

Это сообщение отредактировал(а) wowka19 - 7.5.2014, 03:12
PM MAIL   Вверх
math64
Дата 7.5.2014, 07:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



Все правильно. Ты не вписываешь буквы внутри окружности, а описываешь их снаружи - поэтому длина окружности меньше, чем длина строки.
PM   Вверх
wowka19
Дата 7.5.2014, 08:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Нет. Это невозможно. Я ведь четко вычисляю позицию начала символа на самой окружности - см. рисунок:

user posted image

Немного поясню преобразования:
Код

   qreal angle = 0;
    QFontMetricsF fm(font_);
    QTransform matrix;
    foreach (QChar ch, text_)
    {
        qreal deltaAngle = atan(fm.width(ch) / radius_) * 180/M_PI; // вычисляю угол смещения для след. символа, исходя из ширины текущего
        matrix.reset();                          // = E
        matrix.translate(radius_, fm.height()); // просто перемещаю, чтобы за boundingRect() не выходить (временно)
        matrix.translate(0, radius_); // перехожу к центру окр. чтобы повернуть относит этого самого центра
        matrix.rotate(angle); // поворот на угол, чтобы миновать пред. символ
        matrix.translate(0, -radius_); // возвращаюсь на линию окружности
        matrix.rotate(deltaAngle/2);  // поворот, чтобы конечная точка символа тоже лежала на окружности (поэтому: а)будет хорда, б)=>вписанный многоугольник (неправильный))
        painter.setWorldTransform(matrix); //применим преобразования
        painter.drawText(0,0, ch); // рисуем символ
        angle += deltaAngle; // увеличиваем угол след. символа на угол текущего (только что отрисованного)
    }
    qDebug() << angle / 360 * 2*M_PI*radius_; (2)
    qDebug() << fm.width(text_); (3)


На примере "ШШШШ": как видно надпись занимает без малого половину окружности. В строке (2) участвующий в вычислении угол охвата всей надписи как раз равен ~171 градусу, что похоже на правду, в то время как участвующий в (3) fm.width(text_) будет охватывать fm.width(text_) / 2*M_PI*radius_ * 360 градусов, что в итоге (я считал) дает больше 180 градусов.
Что не так?

Это сообщение отредактировал(а) wowka19 - 7.5.2014, 08:54
PM MAIL   Вверх
math64
Дата 7.5.2014, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



У тебя буквы наезжают друг на друга - ты вычисляешь угол исходя из того, что буквы будут вне окружности, а выводишь их по хорде.
Для расчета угла по хорде нужно использовать не арктангенс, а арксинус
Код

qreal deltaAngle = 2 * asin(fm.width(ch) / 2 / radius_) * 180/M_PI;
...
matrix.rotate(angle + deltaAngle / 2);
matrix.translate(0, -radius_*cos(deltaAngle / 2 * M_PI / 180) );



Это сообщение отредактировал(а) math64 - 7.5.2014, 08:54
PM   Вверх
wowka19
Дата 7.5.2014, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Не выходит - символы еще сильнее наезжают друг на друга
PM MAIL   Вверх
math64
Дата 7.5.2014, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



А, да забыл: нужно выравнивение по центру или
Код

matrix.translate(- fm.width(ch) / 2, -radius_*cos(deltaAngle / 2 * M_PI / 180) );

PM   Вверх
wowka19
Дата 8.5.2014, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Спасибо. Получилось. Но matrix я не менял - всего лишь изменил формулу расчета deltaAngle. И правда я считал неверно (запутался). Вот верный расчет:

Код

    qreal angle = 0;
    QTransform matrix;
    QFontMetrics fm(font_);
    foreach (QChar ch, text_)
    {
        qreal deltaAngle = 2 * asin(fm.width(ch) / 2 / radius_) * 180/M_PI;

        matrix.reset();
        matrix.translate(0, fm.height()); //temp
        matrix.translate(0, radius_);
        matrix.rotate(angle);
        matrix.translate(0, -radius_);
        matrix.rotate(deltaAngle/2);
        painter.setWorldTransform(matrix);
        painter.drawText(0,0, ch); // !!! 3 !!!

        angle += deltaAngle;
    }


    qDebug() << angle;                 // 1
    qDebug() << fm.width(text_) / (2*M_PI*radius_) * 360; // 2


Теперь (1) > (2), как и должно быть.
Но теперь возникло другое непонятное поведение:

Так как радиус может быть и отрицательным (чтобы текст "гнулся" в другую сторону), то мне для универсальности необходимо сделать так, чтобы символы пересекались с окружностью не крайними нижними точками, а крайними центральными. Для этого, казалось бы пустяка необходимо сместить символ на половину его высоты, т.е. заменить строчку (!!! 3 !!!) 
Код

painter.drawText(0,0, ch)

на
Код

painter.drawText(0, fm.height()/2, ch)

Но символы уползают не на половину высоты а на всю. Лишь поделив высоту на ~4 (painter.drawText(0, fm.height()/4, ch)), я добиваюсь своего. Но почему так???

P.S: я понимаю, что fm.height() - это максимальная высота, но я для теста я использую заглавные буквы Ш: "ШШШШ". И я проверил, что fm.height() почти равна ширине "Ш". Кстати отсюда вытекает вопрос: Какую линию считать за середину (по высоте) надписи, чтобы именно эту (воображаемую) линию изгибать?

Это сообщение отредактировал(а) wowka19 - 8.5.2014, 14:40
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0487 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.