在2D表面上绘制居中文本的算法

时间:2011-10-15 03:35:41

标签: algorithm graphics text 2d surface

我正在寻找稳定的算法来在2D表面上水平和垂直地绘制可能的长文本。这不是特定于语言的,所以如果您能提供任何语言的示例,那将非常有用。

以下是关于我想要绘制的文字和表面的信息:

文字信息:

  • px(行高)中文本的大小,当然小于表面高度
  • 类型面(可能是任何)
  • 从ASCII32到ASCII126的简单字符集
  • 文字可能比较长,单词用空格分隔
  • 文本应该在空格不再适合表面宽度时“自动”断开
  • 文字是英文。

表面信息:

  • 宽度和高度
  • 全局坐标系中的x和y坐标(假设原点位于屏幕的顶角)

我确实实现了自己的方法,但它非常不稳定:文本遍布表面,对齐不正确,有时根本不居中。也搜索了一些好的方法虽然找不到有用的东西。我希望stackoverflow社区可以帮助我。非常感谢你。

3 个答案:

答案 0 :(得分:1)

所以你有几条规则要遵循

  • 居中每一行文字
  • 如果一条线的长度>页面宽度,开始一个新行
  • 垂直居中整个文字

所以你在空格上标记你的输入。您将需要一组字符串和一个currentIndex。而line [currentIndex] + token.length< pageWidth,您可以将标记添加到行[currentIndex]。一旦条件失败,你增加currentIndex并继续。

输入完成后,您将每条线水平居中。您必须以像素为单位计算每条线的宽度。然后你做x = pageWidth / 2 - lineWidth / 2。

然后对文本块高度进行相同的计算,但要考虑所有行(可能使用文本周围的边界矩形)。然后你可以用相同的公式获得y值y = pageHeight / 2 - textHeight / 2

答案 1 :(得分:1)

这种方法在概念上很简单,有点涉及执行。它只涉及几个步骤:

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

答案 2 :(得分:0)

这是一种个人方法。如果文本的长度为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++;
            }
    }
}