Алгоритм рисования центрированного текста на 2D-поверхности - PullRequest
1 голос
/ 15 октября 2011

Я ищу стабильный алгоритм для рисования возможно длинного текста по горизонтали и по центру на двухмерной поверхности. Это не зависит от языка, поэтому, если вы можете привести примеры на любом языке, это будет очень полезно.

Следующая информация, которую я имею о тексте, который я хочу нарисовать, и поверхности:

Текстовая информация:

  • размер текста в пикселях (высота строки), конечно, меньше, чем высота поверхности
  • тип лица (может быть любым, хотя)
  • простой набор символов от ASCII32 до ASCII126
  • текст может быть относительно длинным, слова разделены пробелами
  • текст должен разрываться «автоматически» на пробелах, если он больше не будет соответствовать ширине поверхности
  • текст на английском языке.

Информация о поверхности:

  • ширина и высота
  • координаты x и y в глобальной системе координат (при условии, что начало координат находится в левом верхнем углу экрана)

Я реализовал свой собственный подход, но он был очень нестабильным: текст распространялся по поверхности, выравнивание не корректно, иногда вообще не центрировалось. Также гуглил для некоторых хороших подходов, хотя не мог найти что-то полезное. Я надеюсь, что сообщество stackoverflow может помочь мне. Большое спасибо.

Ответы [ 3 ]

1 голос
/ 15 октября 2011

Подход прост в концепции, немного вовлечен в исполнение. Он включает всего несколько шагов:

Split the text into lines that will fit horizontally
Compute the vertical position of the first line
for each line
    Compute its width and the X position
    Display it at the Y position
    Add the line height to the current Y position

Трудная часть - это первый шаг. Остальное легко.

Если у вас есть шрифт с фиксированной шириной, разделить текст на строки не сложно. Вы просто вычисляете, сколько символов уместится на заданной ширине, индексируете строку для этой позиции и затем возвращаетесь к предыдущему разрыву слова. Захватите подстроку от начала предыдущей строки (или начала строки для первой строки) до этой позиции, и это ваша строка. Повторяйте, пока не дойдете до конца строки.

С шрифтом переменной ширины все немного сложнее, потому что вы не можете просто индексировать в строку n * character_width символов. Вместо этого вы должны угадывать, тестировать, уточнять догадки и т. Д. В каждой графической подсистеме, с которой я работал, был какой-то метод MeasureString, который сообщал бы мне, сколько пикселей потребуется для рендеринга строки с учетом конкретного шрифта. , Учитывая то, что я делал в прошлом:

Divide the surface width by the font's average character width
Index that far into the string, and find the next (or previous) word break.
Measure the string
If the result is wider than the width, go back one word and measure again.
If the result is narrower than the width, go forward one word and measure again.
Repeat the measure/adjust until you find the string that will fit.

Как только вы найдете подходящую подстроку, переместите свой начальный индекс вперед к началу следующей строки и делайте это снова, пока не достигнете конца строки.

Вертикальное центрирование группы линий:

starting_position.Y = (Surface_height - (num_lines * line_height)) / 2

Горизонтальное центрирование линии легко выполняется:

starting_position.X = (Surface_width - Measured_string_width) / 2

Вы должны вычислить starting_position.X для каждой строки. Координата Y увеличивается на line_height для каждой последующей строки.

1 голос
/ 15 октября 2011

Итак, у вас есть пара правил, которым нужно следовать

  • центрирование каждой строки текста
  • если длина строки> ширина страницы, начните новую строку
  • вертикально весь текст по центру

Таким образом, вы токенизируете свой ввод пробелов. Вам понадобится коллекция строк и currentIndex. Хотя lines [currentIndex] + token.length

Как только ввод закончен, вы горизонтально центрируете каждую строку. Вы должны вычислить ширину каждой строки в пикселях. Затем вы делаете x = pageWidth / 2 - lineWidth / 2.

Затем выполните те же вычисления для высоты вашего текстового блока, но с учетом всех строк (возможно, используйте ограничительный прямоугольник вокруг текста). Тогда вы можете получить значение y с той же формулой y = pageHeight / 2 - textHeight / 2

0 голосов
/ 05 июля 2012

Это персональный подход. Это будет работать, если длина текста не превышает 30 символов, а первое слово перед пробелом не длиннее 15 символов. Однако эти характеристики могут быть изменены очень легко. Текст будет сохранен в двухмерном массиве и будет сохранен в 2 строки, если одна строка недостаточно велика. После сохранения текста по центру в двумерном массиве его просто нарисовать. Я надеюсь, что это будет полезно.

char[][] t = new char[2][15];

public void putTextInMatrix(String text) {
    int len = text.length();
    int start;
    if(len<=15) {
        start = (15-len)/2;
        for (int i=0, j=0; i<15; i++)
            if(i<start || i>=len+start)
                t[0][i] = ' ';
            else {
                t[0][i] = text.charAt(j);
                j++;
            }
    }
    else {
        int last = len;
        for (int i=0; i<15; i++) {
            if (text.charAt(i) == ' ')
                last = i;
        }
        start = (15-last)/2;
        for (int i=0, j=0; i<15; i++)
            if(i<start || i>=last+start)
                t[0][i] = ' ';
            else {
                t[0][i] = text.charAt(j);
                j++;
            }

        start = (15-(len-last))/2;
        for (int i=0, j=last+1; i<15; i++)
            if(i<start || j>=len)
                t[1][i] = ' ';
            else {
                t[1][i] = text.charAt(j);
                j++;
            }
    }
}
...