16

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

  • вписать текст в окружность, зная высоту линии - а что за высота? Размер шрифта какой-то заданный или можно его менять? И крайний случай - есть текст наподобие я текст немного треугольнотреугольный, т.е. текст, которым можно нормально заполнить верхнюю часть круга, но который уже не подходит для нижней части круга - что делать? Нормального круга без обрезания слов у нас не получится. И обязательно в верхней части каждая строчка должна быть больше предыдущей? Или главное чтобы границы текста создавали очертание круга? т.е. текст может быть лестнично-круглым – BOPOH Jan 27 '16 at 07:54
  • @BOPOH, да, ньюансов много... Думаю, треугольный текст чтобы заполнял верхнюю часть, Размер шрифта - константа, а радиус круга должен меняться. – Vladyslav Matviienko Jan 27 '16 at 07:57
  • 2
    а если забить на сам круг? смещаем текст в вашем примере вправо - получается треугольник, т.е. если сделать такой треугольник - мы получим примерно круг. "Примерно", т.к. проделав то же самое с ромбом мы точно так же получим тот самый треугольник, но "ромб" с натяжкой можно назвать "кругом". Хотя вставив между словами дополнительное пространство в "ромбе" мы можем получить наш "круг". Такой подход подойдет? Тогда и алгоритм несложный: с начала строки перемещаем текст вверх, а с конца - вниз так, чтобы наш "треугольник" сохранялся. Когда сохранить не получится - получили наш "круг" – BOPOH Jan 27 '16 at 08:50
  • @BOPOH Вспоминается армейское, что в военное время Pi может достигать 4. Так и у вас, при "складывании" круга получается треугольник/ромб ;-) – Kromster Jan 27 '16 at 12:50

2 Answers2

7

По моему тут всё просто. Зная высоту строки и её порядковый номер, мы можем рассчитать необходимую ширину (хорду круга): ширина = корень из (высота*номер)*(2*радиус -высота*номер). (Я могу ошибиться, но я думаю вы способны вычислить длину хорды самостоятельно)
Дальше задача сводится к тому, чтоб вписать текст вы эту ширину.

Если же вы не знаете радиус заранее, вы можете рассчитать его исходя из того, что вам нужно вписать площадь текста в площадь круга: радиус = корень из (общая ширина * высота строки / пи)

Добавьте допуски, учитывающие что часть слов придется переносить на следующую строку, чтобы все вписалось. Выравнивание текста нужно по обеим сторонам.

sercxjo
  • 6,904
  • 2
  • 27
  • 57
Darth
  • 13,217
  • .. и повторять пока не впишется все с большим допуском если не вписалось (из-за особенностей переноса например). – Kromster Jan 27 '16 at 08:07
  • @Krom Stern зачем? Можно просто заранее взять достаточно большой допуск, подобранный методом научного тыка. Выравнивание по обоим сторонам нивелирует эффект слишком большого допуска. Так же можно искать самое длинное слово в тексте и брать допуск исходя из него, но имхо это излишне – Darth Jan 27 '16 at 08:18
  • 3
    Как человек работавший в верстке журналов, скажу - одна лишняя буква в полосе способна удлинить текст на несколько строк, и все из-за неудачных переносов. Никто не будет подбирать методом тыка каждый раз, когда у заказчика опять что-то не влезет. Просто добавьте рекурсию с бОльшим запасом в конец - это не сложно. А если брать просто большой допуск, то может оставаться слишком много пустого места в низу круга. Не критикую вас ни в чем, только дополняю ответ. – Kromster Jan 27 '16 at 12:48
  • И нужно писать модуль переносов с учётом нужного языка, т.к. целиковые слова красиво впишутся только при очень мелком шрифте. А выравнивание а-ля Word, делая пробелы между словами разной ширины и всё впишется как нужно – Isaev Feb 03 '16 at 08:50
1

Пусть задан текст и радиус круга. Научимся вписывать текст в круг. Для этого надо будет провести в круге горизонтальные линии на расстоянии высоты шрифта друг от друга. У каждой линии вычисляется её длина внутри круга. Зная длину линии можно понять сколько слов на неё поместится. Строка за строкой заполняем линии. Если текст поместился на линии в круге, возвращаем истину, иначе ложь.

Очевидно, что если для какого-то радиуса r текст поместился, то он поместится и для любого большего радиуса. Аналогично, если текст не помещается в радиус r, то он не поместится и в любой меньший радиус.

Отыщем минимум радиуса при котором текст помещается двоичным поиском. Задача решена. Думаю что на практике будет достаточно десяти попыток, чтобы отыскать нужный радиус.