TextShape Maths

Hello,

I’m failing simple math right now. I want to draw a text with TextShape at a 45 degree angle. But I need the Xojo.Rect surrounding the TextShape. How can I do that?

Why not use a Rectshape and put both in a group2D to rotate them together?

Else you will need to calculate the coordinates of the rotated rect corners and draw it as a polygon.
-karen

Thanks, Karen. Can you please post sample code? I’m not familiar with the Shape2D classes. It would be an advantage if I knew the dimensions of the rectangle before drawing, because I like to output the rectangle centered on a page.

Martin, I posted a routine that finds the minimum bounding rectangle for rotated text, in answer to one of your earlier queries, a couple of years ago. It was in the thread about drawing fan charts.

I did all of that and more yers ago but don’t have teh code handy. Read the docs on the 2D classes.

Group2D’s can be positioned by their center point, so centering the whole thing is not an issue

-karen

example xojo 2019r3.1
but it is not perfect because textheight return same height for “Hello” “jy”
i made a feature request because TextShape did not have a Width,Height

[code]Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint

Var r As New RectShape
r.FillColor = Color.White
r.BorderWidth = 2
r.BorderOpacity = 100
r.BorderColor = Color.Black
r.Width = g.Width
r.Height = g.Height

Var l As Double = Sqrt(g.Widthg.Width + g.Heightg.Height)

Var t As New TextShape
t.HorizontalAlignment = TextShape.Alignment.Center
t.VerticalAlignment = TextShape.Alignment.Center
t.FontSize = 10
t.x = 0
t.y = 0
t.Value = “Hello”
t.Rotation = -ATan2(g.Height,g.Width) ’ -45.0 * 22/7/180

While TextShapeWidth(g,t) < (l - TextShapeHeight(g,t))
t.FontSize = t.FontSize + 0.5
Wend

While TextShapeHeight(g,t) > Min(g.Width,g.Height)
t.FontSize = t.FontSize - 0.5
Wend

g.DrawObject r,g.Width / 2.0, g.Height / 2.0
g.DrawObject t,g.Width / 2.0, g.Height / 2.0

End Sub
[/code]

helpers

[code]Public Function TextShapeWidth(g as Graphics, t as TextShape) as Double
g.FontName = t.FontName
g.FontSize = t.FontSize
g.FontUnit = t.FontUnit

Return g.TextWidth(t.Value)
End Function

Public Function TextShapeHeight(g as Graphics, t as TextShape) as Double
g.FontName = t.FontName
g.FontSize = t.FontSize
g.FontUnit = t.FontUnit

Return g.TextHeight

End Function
[/code]

I’ll have to retract that statement. After reviewing that thread, I see that the bounding box issue was secondary to the main discussion, and I never did post the code. So, here it is now:

Public Function StringPic(Txt As String,font as string, fontsize as integer, fclr as color, bold as boolean, italic as boolean,underline as boolean,rot As Integer) as Picture 'Returns a picture of a rotated string in the smallest bounding box ' Note that angle of rotation, rot, is in integer degrees and is ' counterclockwise from positive x-axis. dim bbW,bbH,x0,y0,r,quadrant As integer dim w,h,w1,w2,h1,h2,a As Double Dim pTest as new Picture(1,1) dim s As new StringShape dim rt as new RectShape Const pi=3.14159265358979 Const radianConversion=-pi/180 s.TextFont=font s.Bold=bold s.Italic=italic s.Underline=underline s.TextSize=fontsize s.Text=Txt s.Border=50 s.BorderWidth=2 s.FillColor=fclr s.BorderColor=&c000000 s.HorizontalAlignment = StringShape.Alignment.Left s.VerticalAlignment = StringShape.Alignment.Top 'Test picture pTest is used for measuring string width and height pTest.Graphics.TextFont = s.TextFont pTest.Graphics.TextSize = s.TextSize pTest.Graphics.TextUnit = s.TextUnit pTest.Graphics.Bold=bold pTest.Graphics.Italic=italic pTest.Graphics.Underline=underline 'Get the width and Height of the unrotated text w = pTest.Graphics.StringWidth(s.Text) h = pTest.Graphics.StringHeight(s.Text,10000) s.Rotation=rot*radianConversion 'Set mask parameters rt.Width=w rt.Height=h rt.Rotation=rot*radianConversion rt.FillColor=&cffffff 'Rotation angle may be in range -360 to +360 'So, normalize it to the range 0..359 degrees r=rot while r<0 r=r+360 wend r=r mod 360 'Get quadrant 1..4 of angle quadrant=1+r\\90 'Get the angle within the quadrant r=r mod 90 'Convert rotation angle to radians and calculate 'principal parameters of rotated text a=-r*radianConversion h1=h*cos(a)+0.5 h2=w*sin(a)+0.5 w1=h*sin(a)+0.5 w2=w*cos(a)+0.5 'Calculate bounding box width and height bbW & bbH ' and text origin x0, y0 from principal dimensions select case quadrant case 1 bbW=w1+w2 bbH=h1+h2 x0=w1 y0=bbH case 2 bbW=h1+h2 bbH=w1+w2 y0=w2 x0=bbW case 3 bbW=w1+w2 bbH=h1+h2 x0=w2 y0=0 case 4 bbW=h1+h2 bbH=w1+w2 x0=0 y0=w1 end select 'Create an exactly sized bounding box for the text dim sPic As new Picture(bbW,bbH) 'and draw the text in it sPic.Graphics.DrawObject(s,x0,y0) 'Note that the exact centre of the text will always be at the exact ' centre of the bounding box. This makes it easy to position. Return sPic End Function

Note that the variables bbW and bbH are the width and height of the bounding box.

Hi everyone,

thanks for your messages. I have now written myself a method that will serve my purpose. I don’t even need a surrounding rectangle anymore, which I only wanted to use for positioning the rotated text within a graphics object. This was a wrong/unnecessary approach. The following code prints any text centered.

[code]Sub DrawRotatedText(g As Graphics, txt As String, degree As Double)
Const pi = 3.14159265358979
Const radianConversion = -pi / 180

Var shape As New TextShape
shape.Bold = g.Bold
shape.FillColor = g.DrawingColor
shape.FontName = g.FontName
shape.FontSize = g.FontSize
shape.FontUnit = g.FontUnit
shape.Italic = g.Italic
shape.Underline = g.Underline
shape.Value = txt
shape.VerticalAlignment = TextShape.Alignment.Center

Var group As New Group2D
group.AddObject(shape)
group.X = g.Width / 2
group.Y = g.Height / 2
group.Rotation = degree * radianConversion
g.DrawObject(group)
End Sub[/code]
Canvas Paint-Event:

Sub Paint(g As Graphics, areas() As REALbasic.Rect) g.FontSize = 72 g.FontName = "Arial" DrawRotatedText(g, "Hello World", 45) End Sub