Как выровнять ориентированный текст по вертикали или по горизонтали?
Я пишу функцию, которая рисует текст на холсте. Функция поддерживает выравнивание по вертикали и горизонтали, а также ориентацию текста. Моя проблема в том, что не могу рассчитать правильное выравнивание, когда текст ориентирован. Это заголовок:
procedure drawText(canvas: TCanvas; pos: TPoint; Text: string;
FontName: TFontName; FontSize: integer; FontColor: TColor; Angle: integer;
Halign: THorizontalAlignement; Valign: TVerticalAlignement);
Halign
может быть слева, справа или по центру, Valign
может быть сверху, снизу или по центру.
Все работает хорошо для простого неориентированного текста с:
h := TextWidth(Text);
case Halign of
haLeft: // do nothing;
;
haRight: x := x - h;
haCenter: x := x - ( h div 2 );
end;
v := TextHeight(Text);
case Valign of
vaTop: // do nothing;
;
vaBottom: y := y - v;
vaCenter: y := y - ( v div 2 );
end;
Font.Orientation := Angle;
textOut(x, y, Text );
Я предпринял много попыток определить, что и куда идет, и мне удалось расположить вертикальный текст в соответствии с его параметрами выравнивания, но горизонтальный был не на своем месте.
Я знаю, что это связано с ориентацией, шириной и высотой, но я не могу понять, как с этим справиться.
Пример при вызове процедуры для правила горизонтали:
drawText( bmp.canvas, point( x, viewOption.padding - DocumentRuleTextMargin),
inttoStr( x ), 'arial', 8, clBLack, 0, haCenter, vaBottom );
Вызов процедуры для правила Vertical (тот, кто раздражает): drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y), inttostr( y), 'arial', 8, clBlack, 900, haCenter, vaBottom);
вот результат:
я попытался избавиться от этого, изменив знаки в расчете позиции y процедуры следующим образом:
v := TextHeight(Text);
case Valign of
vaTop: // do nothing;
;
vaBottom: y := y + v;
vaCenter: y := y + ( v div 2 );
end;
и результат лучше для вертикального правила, а худший для горизонтального:
3 ответа
Проблема в том, что ширина и высота не изменяются при вращении текста.
При использовании поворота на 90° функция textHeight возвращает фактическую (видимую) ширину. То же самое для textWidth, который представляет видимую высоту.
В этом случае невозможно центрировать вертикально и горизонтально повернутый на 90° текст, используя ту же формулу, что и горизонтальный текст (т. Е. Вычитание половины ширины до позиции x приведет к слишком большому смещению).
Поскольку я управляю только вертикальным и горизонтальным текстом, я буду использовать обходной путь, проверяя свойство ориентации. После 900 я переключаю результаты textHeight и textwidth для вычисления выровненного положения текста.
ОК - просто не сработало. То, что вам нужно сделать, это найти центр вашего текста и вычислить "Слева вверху" после поворота. Проблема в том, что я не знаю, на какую точку ориентирован шрифт - наверное, слева вверху. Если так, то ваша функция становится:
// get centre
case Halign of
haLeft: x1 := x + (h div 2);
haRight: x1 := x - (h div 2);
haCenter: x1 := x; // do nothing
end;
v := TextHeight(Text);
case Valign of
vaTop: y1 := y + (v div 2);
vaBottom: y1 := y - (v div 2);
vaCenter: y1 := y; // do nothing
end;
Font.Orientation := Angle;
// calculate new top left - depending on whether you are using firemonkey
// or VCL you may need to convert to floats and/or use Cosint
// x := x1 - (w/2)*CosD(Angle) - (h/2)*SinD(Angle);
x := x1 - ((w * CosInt(Angle * 10)) - (h*SinInt(Angle*10)) div 2000);
//y := y1 - (w/2)*SinD(Angle) + (h/2)*CosD(Angle);
y := y1 - ((w * SinInt(Angle * 10)) - (h*CosInt(Angle*10)) div 2000);
textOut(x, y, Text );
Поскольку вы используете Div в своем коде, я предполагаю, что вы используете VCL.
Я предлагаю вам поискать SinInt для объяснения умножения и деления в этом. комментарии показывают версию с плавающей запятой, которую вы бы использовали в Firemonkey.
Я не проверял этот код - я просто пытаюсь показать математику. Вам нужно будет настроить себя.
Я думаю, что вертикальное правило в вашем случае должно быть
drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaCenter);
потому что вы пытаетесь настроить на галочки, и они должны быть по центру. Изменение вашего алгоритма переместило вертикальные позиции, как и ожидалось, так что похоже, что ваш исходный алгоритм верен - только ваше применение неверно.