Reputation: 127
I am writing a function that draws text on a canvas. The function supports alignment vertical and horizontal, and also text orientation. My problem is that can't calculate proper alignment when text is oriented. This is the header:
procedure drawText(canvas: TCanvas; pos: TPoint; Text: string;
FontName: TFontName; FontSize: integer; FontColor: TColor; Angle: integer;
Halign: THorizontalAlignement; Valign: TVerticalAlignement);
Halign
can be left, right or center, Valign
can be top, bottom or center.
Everything works well for a simple non oriented text with:
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 );
I have made many attempts to determine what goes where, and I have managed to position vertical text according to its alignment parameters, but the horizontal one was misplaced.
I know it is related to orientation and width and height, but i cannot figure out properly how to deal with it.
Example when calling the procedure for the horitontal rule:
drawText( bmp.canvas, point( x, viewOption.padding - DocumentRuleTextMargin),
inttoStr( x ), 'arial', 8, clBLack, 0, haCenter, vaBottom );
Calling the procedure for the Vertical rule (the one who is annoying): drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaBottom);
here is the result :
i tried to get rid of this by modifying the signs in the calculation of the y position of the procedure like this :
v := TextHeight(Text);
case Valign of
vaTop: // do nothing;
;
vaBottom: y := y + v;
vaCenter: y := y + ( v div 2 );
end;
and the result is better for vertical rule, while worst for horizontal one :
Upvotes: 1
Views: 2836
Reputation: 6013
OK - simple did not work. What you need to do, then, is find where the centre of your text should be and calculate 'Top left' from there after rotation. The problem is that I don't know which point the font orientates around - I guess top left. Assuming so then your function becomes:
// 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 );
Since you use Div in your code I am guessing that you are using VCL.
I suggest that you look up SinInt for an explanation of the multiplication and division in this. the comments show the floating point version that you would use in Firemonkey.
I have not tested this code - I am just trying to show the maths. You will need to fine tune yourself.
Upvotes: 2
Reputation: 127
The problem is that width and height does not change while rotating the text.
When using a 90° rotation, what returns textHeight function is the actual(visible) width. Same thing for textWidth that represents the visible height.
In this case, it is not possible to center vertically and horizontally a 90° rotated text using the same formula than an horizontal text ( i.e : substracting half of the width to the x position will result in a too big displacement ).
Since i only manage vertical and horizontal text, i will use a workaround by testing the orientation property. When 900 then i switch textHeight and textwidth results to calculate the aligned position of the text.
Upvotes: 0
Reputation: 6013
I think that the vertical rule in your case should be
drawText( bmp.canvas, Point( x - CDocumentRuleTextMargin, y ), inttostr( y ), 'arial', 8, clBlack, 900, haCenter, vaCenter);
because you are trying to align to the checkmarks, and they need to be centred. Changing your algorithm moved the vertical positions as expected so it looks like your original algorithm is correct - just your application of it is wrong.
Upvotes: 0